CLITool: Port PluginManager to use CLITool
In order to unify the handling and reuse the CLITool infrastructure the plugin manager should make use of this as well. This obsolets the -i and --install options but requires the user to use `install` as the first argument of the CLI. This is basically just a port of the existing functionality, which is also the reason why this is not a refactoring of the plugin manager, which will come in a separate commit.
This commit is contained in:
parent
0cf9c3268c
commit
2f54b89a23
|
@ -24,6 +24,7 @@ import org.elasticsearch.ElasticsearchTimeoutException;
|
|||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.SuppressForbidden;
|
||||
import org.elasticsearch.common.cli.Terminal;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
|
||||
import java.io.*;
|
||||
|
@ -135,22 +136,12 @@ public class HttpDownloadHelper {
|
|||
/**
|
||||
* verbose progress system prints to some output stream
|
||||
*/
|
||||
@SuppressForbidden(reason = "System#out")
|
||||
public static class VerboseProgress implements DownloadProgress {
|
||||
private int dots = 0;
|
||||
// CheckStyle:VisibilityModifier OFF - bc
|
||||
PrintWriter writer;
|
||||
// CheckStyle:VisibilityModifier ON
|
||||
|
||||
/**
|
||||
* Construct a verbose progress reporter.
|
||||
*
|
||||
* @param out the output stream.
|
||||
*/
|
||||
public VerboseProgress(PrintStream out) {
|
||||
this.writer = new PrintWriter(out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a verbose progress reporter.
|
||||
*
|
||||
|
|
|
@ -22,20 +22,17 @@ package org.elasticsearch.plugins;
|
|||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterators;
|
||||
|
||||
import org.apache.lucene.util.IOUtils;
|
||||
import org.elasticsearch.*;
|
||||
import org.elasticsearch.ElasticsearchTimeoutException;
|
||||
import org.elasticsearch.ExceptionsHelper;
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.bootstrap.JarHell;
|
||||
import org.elasticsearch.common.SuppressForbidden;
|
||||
import org.elasticsearch.common.cli.Terminal;
|
||||
import org.elasticsearch.common.collect.Tuple;
|
||||
import org.elasticsearch.common.http.client.HttpDownloadHelper;
|
||||
import org.elasticsearch.common.io.FileSystemUtils;
|
||||
import org.elasticsearch.common.logging.log4j.LogConfigurator;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.node.internal.InternalSettingsPreparer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
@ -52,27 +49,18 @@ import java.util.zip.ZipEntry;
|
|||
import java.util.zip.ZipInputStream;
|
||||
|
||||
import static org.elasticsearch.common.Strings.hasLength;
|
||||
import static org.elasticsearch.common.cli.Terminal.Verbosity.VERBOSE;
|
||||
import static org.elasticsearch.common.io.FileSystemUtils.moveFilesWithoutOverwriting;
|
||||
import static org.elasticsearch.common.settings.Settings.Builder.EMPTY_SETTINGS;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class PluginManager {
|
||||
public static final class ACTION {
|
||||
public static final int NONE = 0;
|
||||
public static final int INSTALL = 1;
|
||||
public static final int REMOVE = 2;
|
||||
public static final int LIST = 3;
|
||||
}
|
||||
|
||||
public enum OutputMode {
|
||||
DEFAULT, SILENT, VERBOSE
|
||||
}
|
||||
|
||||
// By default timeout is 0 which means no timeout
|
||||
public static final TimeValue DEFAULT_TIMEOUT = TimeValue.timeValueMillis(0);
|
||||
|
||||
private static final ImmutableSet<String> BLACKLIST = ImmutableSet.<String>builder()
|
||||
.add("elasticsearch",
|
||||
"elasticsearch.bat",
|
||||
|
@ -81,7 +69,7 @@ public class PluginManager {
|
|||
"plugin.bat",
|
||||
"service.bat").build();
|
||||
|
||||
private static final ImmutableSet<String> OFFICIAL_PLUGINS = ImmutableSet.<String>builder()
|
||||
static final ImmutableSet<String> OFFICIAL_PLUGINS = ImmutableSet.<String>builder()
|
||||
.add(
|
||||
"elasticsearch-analysis-icu",
|
||||
"elasticsearch-analysis-kuromoji",
|
||||
|
@ -108,9 +96,9 @@ public class PluginManager {
|
|||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
public void downloadAndExtract(String name) throws IOException {
|
||||
public void downloadAndExtract(String name, Terminal terminal) throws IOException {
|
||||
if (name == null) {
|
||||
throw new IllegalArgumentException("plugin name must be supplied with --install [name].");
|
||||
throw new IllegalArgumentException("plugin name must be supplied with install [name].");
|
||||
}
|
||||
HttpDownloadHelper downloadHelper = new HttpDownloadHelper();
|
||||
boolean downloaded = false;
|
||||
|
@ -118,7 +106,7 @@ public class PluginManager {
|
|||
if (outputMode == OutputMode.SILENT) {
|
||||
progress = new HttpDownloadHelper.NullProgress();
|
||||
} else {
|
||||
progress = new HttpDownloadHelper.VerboseProgress(SysOut.getOut());
|
||||
progress = new HttpDownloadHelper.VerboseProgress(terminal.writer());
|
||||
}
|
||||
|
||||
if (!Files.isWritable(environment.pluginsFile())) {
|
||||
|
@ -132,13 +120,13 @@ public class PluginManager {
|
|||
// extract the plugin
|
||||
final Path extractLocation = pluginHandle.extractedDir(environment);
|
||||
if (Files.exists(extractLocation)) {
|
||||
throw new IOException("plugin directory " + extractLocation.toAbsolutePath() + " already exists. To update the plugin, uninstall it first using --remove " + name + " command");
|
||||
throw new IOException("plugin directory " + extractLocation.toAbsolutePath() + " already exists. To update the plugin, uninstall it first using remove " + name + " command");
|
||||
}
|
||||
|
||||
// first, try directly from the URL provided
|
||||
if (url != null) {
|
||||
URL pluginUrl = new URL(url);
|
||||
log("Trying " + pluginUrl.toExternalForm() + "...");
|
||||
terminal.println("Trying %s ...", pluginUrl.toExternalForm());
|
||||
try {
|
||||
downloadHelper.download(pluginUrl, pluginFile, progress, this.timeout);
|
||||
downloaded = true;
|
||||
|
@ -146,7 +134,7 @@ public class PluginManager {
|
|||
throw e;
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
log("Failed: " + ExceptionsHelper.detailedMessage(e));
|
||||
terminal.println("Failed: %s", ExceptionsHelper.detailedMessage(e));
|
||||
}
|
||||
} else {
|
||||
if (PluginHandle.isOfficialPlugin(pluginHandle.repo, pluginHandle.user, pluginHandle.version)) {
|
||||
|
@ -157,7 +145,7 @@ public class PluginManager {
|
|||
if (!downloaded) {
|
||||
// We try all possible locations
|
||||
for (URL url : pluginHandle.urls()) {
|
||||
log("Trying " + url.toExternalForm() + "...");
|
||||
terminal.println("Trying %s ...", url.toExternalForm());
|
||||
try {
|
||||
downloadHelper.download(url, pluginFile, progress, this.timeout);
|
||||
downloaded = true;
|
||||
|
@ -165,7 +153,7 @@ public class PluginManager {
|
|||
} catch (ElasticsearchTimeoutException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
debug("Failed: " + ExceptionsHelper.detailedMessage(e));
|
||||
terminal.println(VERBOSE, "Failed: %s", ExceptionsHelper.detailedMessage(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -181,9 +169,7 @@ public class PluginManager {
|
|||
final List<URL> jars = new ArrayList<>();
|
||||
ClassLoader loader = PluginManager.class.getClassLoader();
|
||||
if (loader instanceof URLClassLoader) {
|
||||
for (URL url : ((URLClassLoader) loader).getURLs()) {
|
||||
jars.add(url);
|
||||
}
|
||||
Collections.addAll(jars, ((URLClassLoader) loader).getURLs());
|
||||
}
|
||||
|
||||
// add any jars we find in the plugin to the list
|
||||
|
@ -199,7 +185,7 @@ public class PluginManager {
|
|||
|
||||
// check combined (current classpath + new jars to-be-added)
|
||||
try {
|
||||
JarHell.checkJarHell(jars.toArray(new URL[0]));
|
||||
JarHell.checkJarHell(jars.toArray(new URL[jars.size()]));
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
@ -240,24 +226,24 @@ public class PluginManager {
|
|||
|
||||
});
|
||||
}
|
||||
log("Installed " + name + " into " + extractLocation.toAbsolutePath());
|
||||
terminal.println("Installed %s into %s", name, extractLocation.toAbsolutePath());
|
||||
} catch (Exception e) {
|
||||
log("failed to extract plugin [" + pluginFile + "]: " + ExceptionsHelper.detailedMessage(e));
|
||||
terminal.printError("failed to extract plugin [%s]: %s", pluginFile, ExceptionsHelper.detailedMessage(e));
|
||||
return;
|
||||
} finally {
|
||||
try {
|
||||
Files.delete(pluginFile);
|
||||
} catch (Exception ex) {
|
||||
log("Failed to delete plugin file" + pluginFile + " " + ex);
|
||||
terminal.printError("Failed to delete plugin file %s %s", pluginFile, ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (FileSystemUtils.hasExtensions(extractLocation, ".java")) {
|
||||
debug("Plugin installation assumed to be site plugin, but contains source code, aborting installation...");
|
||||
terminal.printError("Plugin installation assumed to be site plugin, but contains source code, aborting installation...");
|
||||
try {
|
||||
IOUtils.rm(extractLocation);
|
||||
} catch(Exception ex) {
|
||||
debug("Failed to remove site plugin from path " + extractLocation + " - " + ex.getMessage());
|
||||
terminal.printError("Failed to remove site plugin from path %s - %s", extractLocation, ex.getMessage());
|
||||
}
|
||||
throw new IllegalArgumentException("Plugin installation assumed to be site plugin, but contains source code, aborting installation.");
|
||||
}
|
||||
|
@ -267,7 +253,7 @@ public class PluginManager {
|
|||
Path binFile = extractLocation.resolve("bin");
|
||||
if (Files.isDirectory(binFile)) {
|
||||
Path toLocation = pluginHandle.binDir(environment);
|
||||
debug("Found bin, moving to " + toLocation.toAbsolutePath());
|
||||
terminal.println(VERBOSE, "Found bin, moving to %s", toLocation.toAbsolutePath());
|
||||
if (Files.exists(toLocation)) {
|
||||
IOUtils.rm(toLocation);
|
||||
}
|
||||
|
@ -298,18 +284,18 @@ public class PluginManager {
|
|||
}
|
||||
});
|
||||
} else {
|
||||
debug("Skipping posix permissions - filestore doesn't support posix permission");
|
||||
terminal.println(VERBOSE, "Skipping posix permissions - filestore doesn't support posix permission");
|
||||
}
|
||||
debug("Installed " + name + " into " + toLocation.toAbsolutePath());
|
||||
terminal.println(VERBOSE, "Installed %s into %s", name, toLocation.toAbsolutePath());
|
||||
potentialSitePlugin = false;
|
||||
}
|
||||
|
||||
Path configFile = extractLocation.resolve("config");
|
||||
if (Files.isDirectory(configFile)) {
|
||||
Path configDestLocation = pluginHandle.configDir(environment);
|
||||
debug("Found config, moving to " + configDestLocation.toAbsolutePath());
|
||||
terminal.println(VERBOSE, "Found config, moving to %s", configDestLocation.toAbsolutePath());
|
||||
moveFilesWithoutOverwriting(configFile, configDestLocation, ".new");
|
||||
debug("Installed " + name + " into " + configDestLocation.toAbsolutePath());
|
||||
terminal.println(VERBOSE, "Installed %s into %s", name, configDestLocation.toAbsolutePath());
|
||||
potentialSitePlugin = false;
|
||||
}
|
||||
|
||||
|
@ -317,13 +303,13 @@ public class PluginManager {
|
|||
// so its probably a _site, and it it does not have a _site in it, move everything to _site
|
||||
if (!Files.exists(extractLocation.resolve("_site"))) {
|
||||
if (potentialSitePlugin && !FileSystemUtils.hasExtensions(extractLocation, ".class", ".jar")) {
|
||||
log("Identified as a _site plugin, moving to _site structure ...");
|
||||
terminal.println(VERBOSE, "Identified as a _site plugin, moving to _site structure ...");
|
||||
Path site = extractLocation.resolve("_site");
|
||||
Path tmpLocation = environment.pluginsFile().resolve(extractLocation.getFileName() + ".tmp");
|
||||
Files.move(extractLocation, tmpLocation);
|
||||
Files.createDirectories(extractLocation);
|
||||
Files.move(tmpLocation, site);
|
||||
debug("Installed " + name + " into " + site.toAbsolutePath());
|
||||
terminal.println(VERBOSE, "Installed " + name + " into " + site.toAbsolutePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -355,9 +341,9 @@ public class PluginManager {
|
|||
return tmp;
|
||||
}
|
||||
|
||||
public void removePlugin(String name) throws IOException {
|
||||
public void removePlugin(String name, Terminal terminal) throws IOException {
|
||||
if (name == null) {
|
||||
throw new IllegalArgumentException("plugin name must be supplied with --remove [name].");
|
||||
throw new IllegalArgumentException("plugin name must be supplied with remove [name].");
|
||||
}
|
||||
PluginHandle pluginHandle = PluginHandle.parse(name);
|
||||
boolean removed = false;
|
||||
|
@ -365,7 +351,7 @@ public class PluginManager {
|
|||
checkForForbiddenName(pluginHandle.name);
|
||||
Path pluginToDelete = pluginHandle.extractedDir(environment);
|
||||
if (Files.exists(pluginToDelete)) {
|
||||
debug("Removing: " + pluginToDelete);
|
||||
terminal.println(VERBOSE, "Removing: %s", pluginToDelete);
|
||||
try {
|
||||
IOUtils.rm(pluginToDelete);
|
||||
} catch (IOException ex){
|
||||
|
@ -376,7 +362,7 @@ public class PluginManager {
|
|||
}
|
||||
pluginToDelete = pluginHandle.distroFile(environment);
|
||||
if (Files.exists(pluginToDelete)) {
|
||||
debug("Removing: " + pluginToDelete);
|
||||
terminal.println(VERBOSE, "Removing: %s", pluginToDelete);
|
||||
try {
|
||||
Files.delete(pluginToDelete);
|
||||
} catch (Exception ex) {
|
||||
|
@ -387,7 +373,7 @@ public class PluginManager {
|
|||
}
|
||||
Path binLocation = pluginHandle.binDir(environment);
|
||||
if (Files.exists(binLocation)) {
|
||||
debug("Removing: " + binLocation);
|
||||
terminal.println(VERBOSE, "Removing: %s", binLocation);
|
||||
try {
|
||||
IOUtils.rm(binLocation);
|
||||
} catch (IOException ex){
|
||||
|
@ -398,9 +384,9 @@ public class PluginManager {
|
|||
}
|
||||
|
||||
if (removed) {
|
||||
log("Removed " + name);
|
||||
terminal.println("Removed %s", name);
|
||||
} else {
|
||||
log("Plugin " + name + " not found. Run plugin --list to get list of installed plugins.");
|
||||
terminal.println("Plugin %s not found. Run plugin --list to get list of installed plugins.", name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -425,253 +411,18 @@ public class PluginManager {
|
|||
}
|
||||
}
|
||||
|
||||
public void listInstalledPlugins() throws IOException {
|
||||
public void listInstalledPlugins(Terminal terminal) throws IOException {
|
||||
Path[] plugins = getListInstalledPlugins();
|
||||
log("Installed plugins in " + environment.pluginsFile().toAbsolutePath() + ":");
|
||||
terminal.println("Installed plugins in %s:", environment.pluginsFile().toAbsolutePath());
|
||||
if (plugins == null || plugins.length == 0) {
|
||||
log(" - No plugin detected");
|
||||
terminal.println(" - No plugin detected");
|
||||
} else {
|
||||
for (int i = 0; i < plugins.length; i++) {
|
||||
log(" - " + plugins[i].getFileName());
|
||||
for (Path plugin : plugins) {
|
||||
terminal.println(" - " + plugin.getFileName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final int EXIT_CODE_OK = 0;
|
||||
private static final int EXIT_CODE_CMD_USAGE = 64;
|
||||
private static final int EXIT_CODE_IO_ERROR = 74;
|
||||
private static final int EXIT_CODE_ERROR = 70;
|
||||
|
||||
public static void main(String[] args) {
|
||||
Tuple<Settings, Environment> initialSettings = InternalSettingsPreparer.prepareSettings(EMPTY_SETTINGS, true, Terminal.DEFAULT);
|
||||
LogConfigurator.configure(initialSettings.v1());
|
||||
|
||||
try {
|
||||
Files.createDirectories(initialSettings.v2().pluginsFile());
|
||||
} catch (IOException e) {
|
||||
displayHelp("Unable to create plugins dir: " + initialSettings.v2().pluginsFile());
|
||||
System.exit(EXIT_CODE_ERROR);
|
||||
}
|
||||
|
||||
String url = null;
|
||||
OutputMode outputMode = OutputMode.DEFAULT;
|
||||
String pluginName = null;
|
||||
TimeValue timeout = DEFAULT_TIMEOUT;
|
||||
int action = ACTION.NONE;
|
||||
|
||||
if (args.length < 1) {
|
||||
displayHelp(null);
|
||||
}
|
||||
|
||||
try {
|
||||
for (int c = 0; c < args.length; c++) {
|
||||
String command = args[c];
|
||||
switch (command) {
|
||||
case "-u":
|
||||
case "--url":
|
||||
// deprecated versions:
|
||||
case "url":
|
||||
case "-url":
|
||||
url = getCommandValue(args, ++c, "--url");
|
||||
// Until update is supported, then supplying a URL implies installing
|
||||
// By specifying this action, we also avoid silently failing without
|
||||
// dubious checks.
|
||||
action = ACTION.INSTALL;
|
||||
break;
|
||||
case "-v":
|
||||
case "--verbose":
|
||||
// deprecated versions:
|
||||
case "verbose":
|
||||
case "-verbose":
|
||||
outputMode = OutputMode.VERBOSE;
|
||||
break;
|
||||
case "-s":
|
||||
case "--silent":
|
||||
// deprecated versions:
|
||||
case "silent":
|
||||
case "-silent":
|
||||
outputMode = OutputMode.SILENT;
|
||||
break;
|
||||
case "-i":
|
||||
case "--install":
|
||||
// deprecated versions:
|
||||
case "install":
|
||||
case "-install":
|
||||
pluginName = getCommandValue(args, ++c, "--install");
|
||||
action = ACTION.INSTALL;
|
||||
break;
|
||||
case "-r":
|
||||
case "--remove":
|
||||
// deprecated versions:
|
||||
case "remove":
|
||||
case "-remove":
|
||||
pluginName = getCommandValue(args, ++c, "--remove");
|
||||
action = ACTION.REMOVE;
|
||||
break;
|
||||
case "-t":
|
||||
case "--timeout":
|
||||
// deprecated versions:
|
||||
case "timeout":
|
||||
case "-timeout":
|
||||
String timeoutValue = getCommandValue(args, ++c, "--timeout");
|
||||
timeout = TimeValue.parseTimeValue(timeoutValue, DEFAULT_TIMEOUT, command);
|
||||
break;
|
||||
case "-l":
|
||||
case "--list":
|
||||
action = ACTION.LIST;
|
||||
break;
|
||||
case "-h":
|
||||
case "--help":
|
||||
displayHelp(null);
|
||||
break;
|
||||
default:
|
||||
displayHelp("Command [" + command + "] unknown.");
|
||||
// Unknown command. We break...
|
||||
System.exit(EXIT_CODE_CMD_USAGE);
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
displayHelp("Error while parsing options: " + e.getClass().getSimpleName() +
|
||||
": " + e.getMessage());
|
||||
System.exit(EXIT_CODE_CMD_USAGE);
|
||||
}
|
||||
|
||||
if (action > ACTION.NONE) {
|
||||
int exitCode = EXIT_CODE_ERROR; // we fail unless it's reset
|
||||
PluginManager pluginManager = new PluginManager(initialSettings.v2(), url, outputMode, timeout);
|
||||
switch (action) {
|
||||
case ACTION.INSTALL:
|
||||
try {
|
||||
pluginManager.log("-> Installing " + Strings.nullToEmpty(pluginName) + "...");
|
||||
pluginManager.downloadAndExtract(pluginName);
|
||||
exitCode = EXIT_CODE_OK;
|
||||
} catch (IOException e) {
|
||||
exitCode = EXIT_CODE_IO_ERROR;
|
||||
pluginManager.log("Failed to install " + pluginName + ", reason: " + e.getMessage());
|
||||
} catch (Throwable e) {
|
||||
exitCode = EXIT_CODE_ERROR;
|
||||
displayHelp("Error while installing plugin, reason: " + e.getClass().getSimpleName() +
|
||||
": " + e.getMessage());
|
||||
}
|
||||
break;
|
||||
case ACTION.REMOVE:
|
||||
try {
|
||||
pluginManager.log("-> Removing " + Strings.nullToEmpty(pluginName) + "...");
|
||||
pluginManager.removePlugin(pluginName);
|
||||
exitCode = EXIT_CODE_OK;
|
||||
} catch (IllegalArgumentException e) {
|
||||
exitCode = EXIT_CODE_CMD_USAGE;
|
||||
pluginManager.log("Failed to remove " + pluginName + ", reason: " + e.getMessage());
|
||||
} catch (IOException e) {
|
||||
exitCode = EXIT_CODE_IO_ERROR;
|
||||
pluginManager.log("Failed to remove " + pluginName + ", reason: " + e.getMessage());
|
||||
} catch (Throwable e) {
|
||||
exitCode = EXIT_CODE_ERROR;
|
||||
displayHelp("Error while removing plugin, reason: " + e.getClass().getSimpleName() +
|
||||
": " + e.getMessage());
|
||||
}
|
||||
break;
|
||||
case ACTION.LIST:
|
||||
try {
|
||||
pluginManager.listInstalledPlugins();
|
||||
exitCode = EXIT_CODE_OK;
|
||||
} catch (Throwable e) {
|
||||
displayHelp("Error while listing plugins, reason: " + e.getClass().getSimpleName() +
|
||||
": " + e.getMessage());
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
pluginManager.log("Unknown Action [" + action + "]");
|
||||
exitCode = EXIT_CODE_ERROR;
|
||||
|
||||
}
|
||||
System.exit(exitCode); // exit here!
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value for the {@code flag} at the specified {@code arg} of the command line {@code args}.
|
||||
* <p />
|
||||
* This is useful to avoid having to check for multiple forms of unset (e.g., " " versus "" versus {@code null}).
|
||||
* @param args Incoming command line arguments.
|
||||
* @param arg Expected argument containing the value.
|
||||
* @param flag The flag whose value is being retrieved.
|
||||
* @return Never {@code null}. The trimmed value.
|
||||
* @throws NullPointerException if {@code args} is {@code null}.
|
||||
* @throws ArrayIndexOutOfBoundsException if {@code arg} is negative.
|
||||
* @throws IllegalStateException if {@code arg} is >= {@code args.length}.
|
||||
* @throws IllegalArgumentException if the value evaluates to blank ({@code null} or only whitespace)
|
||||
*/
|
||||
private static String getCommandValue(String[] args, int arg, String flag) {
|
||||
if (arg >= args.length) {
|
||||
throw new IllegalStateException("missing value for " + flag + ". Usage: " + flag + " [value]");
|
||||
}
|
||||
|
||||
// avoid having to interpret multiple forms of unset
|
||||
String trimmedValue = Strings.emptyToNull(args[arg].trim());
|
||||
|
||||
// If we had a value that is blank, then fail immediately
|
||||
if (trimmedValue == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"value for " + flag + "('" + args[arg] + "') must be set. Usage: " + flag + " [value]");
|
||||
}
|
||||
|
||||
return trimmedValue;
|
||||
}
|
||||
|
||||
private static void displayHelp(String message) {
|
||||
SysOut.println("Usage:");
|
||||
SysOut.println(" -u, --url [plugin location] : Set exact URL to download the plugin from");
|
||||
SysOut.println(" -i, --install [plugin name] : Downloads and installs listed plugins [*]");
|
||||
SysOut.println(" -t, --timeout [duration] : Timeout setting: 30s, 1m, 1h... (infinite by default)");
|
||||
SysOut.println(" -r, --remove [plugin name] : Removes listed plugins");
|
||||
SysOut.println(" -l, --list : List installed plugins");
|
||||
SysOut.println(" -v, --verbose : Prints verbose messages");
|
||||
SysOut.println(" -s, --silent : Run in silent mode");
|
||||
SysOut.println(" -h, --help : Prints this help message");
|
||||
SysOut.newline();
|
||||
SysOut.println(" [*] Plugin name could be:");
|
||||
SysOut.println(" elasticsearch-plugin-name for Elasticsearch 2.0 Core plugin (download from download.elastic.co)");
|
||||
SysOut.println(" elasticsearch/plugin/version for elasticsearch commercial plugins (download from download.elastic.co)");
|
||||
SysOut.println(" groupId/artifactId/version for community plugins (download from maven central or oss sonatype)");
|
||||
SysOut.println(" username/repository for site plugins (download from github master)");
|
||||
SysOut.newline();
|
||||
SysOut.println("Elasticsearch Core plugins:");
|
||||
for (String o : OFFICIAL_PLUGINS) {
|
||||
SysOut.println(" - " + o);
|
||||
}
|
||||
|
||||
if (message != null) {
|
||||
SysOut.newline();
|
||||
SysOut.println("Message:");
|
||||
SysOut.println(" " + message);
|
||||
}
|
||||
}
|
||||
|
||||
private void debug(String line) {
|
||||
if (outputMode == OutputMode.VERBOSE) SysOut.println(line);
|
||||
}
|
||||
|
||||
private void log(String line) {
|
||||
if (outputMode != OutputMode.SILENT) SysOut.println(line);
|
||||
}
|
||||
|
||||
@SuppressForbidden(reason = "System#out")
|
||||
static class SysOut {
|
||||
|
||||
public static void newline() {
|
||||
System.out.println();
|
||||
}
|
||||
public static void println(String msg) {
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
public static PrintStream getOut() {
|
||||
return System.out;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class to extract properly user name, repository name, version and plugin name
|
||||
* from plugin name given by a user.
|
||||
|
|
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.plugins;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
import org.elasticsearch.common.cli.CliTool;
|
||||
import org.elasticsearch.common.cli.CliToolConfig;
|
||||
import org.elasticsearch.common.cli.Terminal;
|
||||
import org.elasticsearch.common.collect.Tuple;
|
||||
import org.elasticsearch.common.logging.log4j.LogConfigurator;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.node.internal.InternalSettingsPreparer;
|
||||
import org.elasticsearch.plugins.PluginManager.OutputMode;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
|
||||
import static org.elasticsearch.common.cli.CliToolConfig.Builder.cmd;
|
||||
import static org.elasticsearch.common.cli.CliToolConfig.Builder.option;
|
||||
import static org.elasticsearch.common.settings.Settings.EMPTY;
|
||||
|
||||
public class PluginManagerCliParser extends CliTool {
|
||||
|
||||
// By default timeout is 0 which means no timeout
|
||||
public static final TimeValue DEFAULT_TIMEOUT = TimeValue.timeValueMillis(0);
|
||||
|
||||
private static final CliToolConfig CONFIG = CliToolConfig.config("plugin", PluginManagerCliParser.class)
|
||||
.cmds(ListPlugins.CMD, Install.CMD, Remove.CMD)
|
||||
.build();
|
||||
|
||||
public static void main(String[] args) {
|
||||
Tuple<Settings, Environment> initialSettings = InternalSettingsPreparer.prepareSettings(EMPTY, true, Terminal.DEFAULT);
|
||||
LogConfigurator.configure(initialSettings.v1());
|
||||
int status = new PluginManagerCliParser().execute(args);
|
||||
System.exit(status);
|
||||
}
|
||||
|
||||
public PluginManagerCliParser() {
|
||||
super(CONFIG);
|
||||
}
|
||||
|
||||
public PluginManagerCliParser(Terminal terminal) {
|
||||
super(CONFIG, terminal);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Command parse(String cmdName, CommandLine cli) throws Exception {
|
||||
switch (cmdName.toLowerCase(Locale.ROOT)) {
|
||||
case Install.NAME:
|
||||
return Install.parse(terminal, cli);
|
||||
case ListPlugins.NAME:
|
||||
return ListPlugins.parse(terminal, cli);
|
||||
case Remove.NAME:
|
||||
return Remove.parse(terminal, cli);
|
||||
default:
|
||||
assert false : "can't get here as cmd name is validated before this method is called";
|
||||
return exitCmd(ExitStatus.USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* List all installed plugins
|
||||
*/
|
||||
static class ListPlugins extends CliTool.Command {
|
||||
|
||||
private static final String NAME = "list";
|
||||
|
||||
private static final CliToolConfig.Cmd CMD = cmd(NAME, ListPlugins.class).build();
|
||||
private final OutputMode outputMode;
|
||||
|
||||
public static Command parse(Terminal terminal, CommandLine cli) {
|
||||
OutputMode outputMode = OutputMode.DEFAULT;
|
||||
if (cli.hasOption("s")) {
|
||||
outputMode = OutputMode.SILENT;
|
||||
}
|
||||
if (cli.hasOption("v")) {
|
||||
outputMode = OutputMode.VERBOSE;
|
||||
}
|
||||
|
||||
return new ListPlugins(terminal, outputMode);
|
||||
}
|
||||
|
||||
ListPlugins(Terminal terminal, OutputMode outputMode) {
|
||||
super(terminal);
|
||||
this.outputMode = outputMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExitStatus execute(Settings settings, Environment env) throws Exception {
|
||||
PluginManager pluginManager = new PluginManager(env, null, outputMode, DEFAULT_TIMEOUT);
|
||||
pluginManager.listInstalledPlugins(terminal);
|
||||
return ExitStatus.OK;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a plugin
|
||||
*/
|
||||
static class Remove extends CliTool.Command {
|
||||
|
||||
private static final String NAME = "remove";
|
||||
|
||||
private static final CliToolConfig.Cmd CMD = cmd(NAME, Remove.class).build();
|
||||
|
||||
public static Command parse(Terminal terminal, CommandLine cli) {
|
||||
String[] args = cli.getArgs();
|
||||
if (args.length == 0) {
|
||||
return exitCmd(ExitStatus.USAGE, terminal, "plugin name is missing (type -h for help)");
|
||||
}
|
||||
|
||||
OutputMode outputMode = OutputMode.DEFAULT;
|
||||
if (cli.hasOption("s")) {
|
||||
outputMode = OutputMode.SILENT;
|
||||
}
|
||||
if (cli.hasOption("v")) {
|
||||
outputMode = OutputMode.VERBOSE;
|
||||
}
|
||||
|
||||
return new Remove(terminal, outputMode, args[0]);
|
||||
}
|
||||
|
||||
private OutputMode outputMode;
|
||||
final String pluginName;
|
||||
|
||||
Remove(Terminal terminal, OutputMode outputMode, String pluginToRemove) {
|
||||
super(terminal);
|
||||
this.outputMode = outputMode;
|
||||
this.pluginName = pluginToRemove;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExitStatus execute(Settings settings, Environment env) throws Exception {
|
||||
|
||||
PluginManager pluginManager = new PluginManager(env, null, outputMode, DEFAULT_TIMEOUT);
|
||||
terminal.println("-> Removing " + Strings.nullToEmpty(pluginName) + "...");
|
||||
pluginManager.removePlugin(pluginName, terminal);
|
||||
return ExitStatus.OK;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs a plugin
|
||||
*/
|
||||
static class Install extends Command {
|
||||
|
||||
private static final String NAME = "install";
|
||||
|
||||
private static final CliToolConfig.Cmd CMD = cmd(NAME, Install.class)
|
||||
.options(option("u", "url").required(false).hasArg(true))
|
||||
.options(option("t", "timeout").required(false).hasArg(false))
|
||||
.build();
|
||||
|
||||
static Command parse(Terminal terminal, CommandLine cli) {
|
||||
String[] args = cli.getArgs();
|
||||
if ((args == null) || (args.length == 0)) {
|
||||
return exitCmd(ExitStatus.USAGE, terminal, "plugin name is missing (type -h for help)");
|
||||
}
|
||||
|
||||
String name = args[0];
|
||||
TimeValue timeout = TimeValue.parseTimeValue(cli.getOptionValue("t"), DEFAULT_TIMEOUT, "cli");
|
||||
String url = cli.getOptionValue("u");
|
||||
|
||||
OutputMode outputMode = OutputMode.DEFAULT;
|
||||
if (cli.hasOption("s")) {
|
||||
outputMode = OutputMode.SILENT;
|
||||
}
|
||||
if (cli.hasOption("v")) {
|
||||
outputMode = OutputMode.VERBOSE;
|
||||
}
|
||||
|
||||
return new Install(terminal, name, outputMode, url, timeout);
|
||||
}
|
||||
|
||||
final String name;
|
||||
private OutputMode outputMode;
|
||||
final String url;
|
||||
final TimeValue timeout;
|
||||
|
||||
Install(Terminal terminal, String name, OutputMode outputMode, String url, TimeValue timeout) {
|
||||
super(terminal);
|
||||
this.name = name;
|
||||
this.outputMode = outputMode;
|
||||
this.url = url;
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExitStatus execute(Settings settings, Environment env) throws Exception {
|
||||
PluginManager pluginManager = new PluginManager(env, url, outputMode, timeout);
|
||||
terminal.println("-> Installing " + Strings.nullToEmpty(name) + "...");
|
||||
pluginManager.downloadAndExtract(name, terminal);
|
||||
return ExitStatus.OK;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
NAME
|
||||
|
||||
install - Install a plugin
|
||||
|
||||
SYNOPSIS
|
||||
|
||||
plugin install <name>
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
This command installs an elasticsearch plugin
|
||||
|
||||
<name> can be one of the official plugins, or refer to a github repository, or to one of the official plugins
|
||||
|
||||
The notation of just specifying a plugin name, downloads an officially supported plugin.
|
||||
|
||||
The notation of 'elasticsearch/plugin/version' allows to easily download a commercial elastic plugin.
|
||||
|
||||
The notation of 'groupId/artifactId/version' refers to community plugins using maven central or sonatype
|
||||
|
||||
The notation of 'username/repository' refers to a github repository.
|
||||
|
||||
EXAMPLES
|
||||
|
||||
plugin install elasticsearch-analysis-kuromoji
|
||||
|
||||
plugin install elasticsearch/shield/latest
|
||||
|
||||
plugin install lmenezes/elasticsearch-kopf
|
||||
|
||||
OFFICIAL PLUGINS
|
||||
|
||||
The following plugins are officially supported and can be installed by just referring to their name
|
||||
|
||||
- elasticsearch-analysis-icu
|
||||
- elasticsearch-analysis-kuromoji
|
||||
- elasticsearch-analysis-phonetic
|
||||
- elasticsearch-analysis-smartcn
|
||||
- elasticsearch-analysis-stempel
|
||||
- elasticsearch-cloud-aws
|
||||
- elasticsearch-cloud-azure
|
||||
- elasticsearch-cloud-gce
|
||||
- elasticsearch-delete-by-query
|
||||
- elasticsearch-lang-javascript
|
||||
- elasticsearch-lang-python
|
||||
|
||||
|
||||
OPTIONS
|
||||
|
||||
-u,--url URL to retrive the plugin from
|
||||
|
||||
-t,--timeout Timeout until the plugin download is abort
|
||||
|
||||
-v,--verbose Verbose output
|
||||
|
||||
-h,--help Shows this message
|
|
@ -0,0 +1,12 @@
|
|||
NAME
|
||||
|
||||
list - List all plugins
|
||||
|
||||
SYNOPSIS
|
||||
|
||||
plugin list
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
This command lists all installed elasticsearch plugins
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
NAME
|
||||
|
||||
remove - Remove a plugin
|
||||
|
||||
SYNOPSIS
|
||||
|
||||
plugin remove <name>
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
This command removes an elasticsearch plugin
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
NAME
|
||||
|
||||
plugin - Manages plugins
|
||||
|
||||
SYNOPSIS
|
||||
|
||||
plugin <command>
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
Manage plugins
|
||||
|
||||
COMMANDS
|
||||
|
||||
install Install a plugin
|
||||
|
||||
remove Remove a plugin
|
||||
|
||||
list List installed plugins
|
||||
|
||||
NOTES
|
||||
|
||||
[*] For usage help on specific commands please type "plugin <command> -h"
|
||||
|
|
@ -49,7 +49,7 @@ public abstract class CliToolTestCase extends ElasticsearchTestCase {
|
|||
System.clearProperty("es.default.path.home");
|
||||
}
|
||||
|
||||
protected static String[] args(String command) {
|
||||
public static String[] args(String command) {
|
||||
if (!Strings.hasLength(command)) {
|
||||
return Strings.EMPTY_ARRAY;
|
||||
}
|
||||
|
|
|
@ -18,17 +18,18 @@
|
|||
*/
|
||||
package org.elasticsearch.plugins;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Predicate;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.lucene.util.IOUtils;
|
||||
import org.apache.lucene.util.LuceneTestCase;
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.ElasticsearchTimeoutException;
|
||||
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
|
||||
import org.elasticsearch.action.admin.cluster.node.info.PluginInfo;
|
||||
import org.elasticsearch.common.cli.CliTool;
|
||||
import org.elasticsearch.common.cli.CliToolTestCase.CaptureOutputTerminal;
|
||||
import org.elasticsearch.common.collect.Tuple;
|
||||
import org.elasticsearch.common.io.Streams;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.node.internal.InternalSettingsPreparer;
|
||||
import org.elasticsearch.rest.RestStatus;
|
||||
|
@ -37,6 +38,8 @@ import org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
|
|||
import org.elasticsearch.test.junit.annotations.Network;
|
||||
import org.elasticsearch.test.rest.client.http.HttpRequestBuilder;
|
||||
import org.elasticsearch.test.rest.client.http.HttpResponse;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -46,14 +49,16 @@ import java.nio.file.Path;
|
|||
import java.nio.file.attribute.PosixFileAttributeView;
|
||||
import java.nio.file.attribute.PosixFileAttributes;
|
||||
import java.nio.file.attribute.PosixFilePermission;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.elasticsearch.common.cli.CliTool.ExitStatus.USAGE;
|
||||
import static org.elasticsearch.common.cli.CliToolTestCase.args;
|
||||
import static org.elasticsearch.common.io.FileSystemUtilsTests.assertFileContent;
|
||||
import static org.elasticsearch.common.settings.Settings.settingsBuilder;
|
||||
import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertDirectoryExists;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertFileExists;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
@ClusterScope(scope = Scope.TEST, numDataNodes = 0, transportClientRatio = 0.0)
|
||||
|
@ -62,20 +67,50 @@ import static org.hamcrest.Matchers.*;
|
|||
// if its in your classpath, then do not use plugins!!!!!!
|
||||
public class PluginManagerTests extends ElasticsearchIntegrationTest {
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testDownloadAndExtract_NullName_ThrowsException() throws IOException {
|
||||
pluginManager(getPluginUrlForResource("plugin_single_folder.zip")).downloadAndExtract(null);
|
||||
private Tuple<Settings, Environment> initialSettings;
|
||||
private CaptureOutputTerminal terminal = new CaptureOutputTerminal();
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
initialSettings = buildInitialSettings();
|
||||
System.setProperty("es.default.path.home", initialSettings.v1().get("path.home"));
|
||||
try {
|
||||
Files.createDirectories(initialSettings.v2().pluginsFile());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
Path binDir = initialSettings.v2().homeFile().resolve("bin");
|
||||
if (!Files.exists(binDir)) {
|
||||
Files.createDirectories(binDir);
|
||||
}
|
||||
Path configDir = initialSettings.v2().configFile();
|
||||
if (!Files.exists(configDir)) {
|
||||
Files.createDirectories(configDir);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@After
|
||||
public void clearPathHome() {
|
||||
System.clearProperty("es.default.path.home");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testThatPluginNameMustBeSupplied() throws IOException {
|
||||
String pluginUrl = getPluginUrlForResource("plugin_single_folder.zip");
|
||||
assertStatus("install --url " + pluginUrl, USAGE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocalPluginInstallSingleFolder() throws Exception {
|
||||
//When we have only a folder in top-level (no files either) we remove that folder while extracting
|
||||
String pluginName = "plugin-test";
|
||||
Tuple<Settings, Environment> initialSettings = buildInitialSettings();
|
||||
downloadAndExtract(pluginName, initialSettings, getPluginUrlForResource("plugin_single_folder.zip"));
|
||||
String pluginUrl = getPluginUrlForResource("plugin_single_folder.zip");
|
||||
String installCommand = String.format(Locale.ROOT, "install %s --url %s", pluginName, pluginUrl);
|
||||
assertStatusOk(installCommand);
|
||||
|
||||
internalCluster().startNode(initialSettings.v1());
|
||||
|
||||
assertPluginLoaded(pluginName);
|
||||
assertPluginAvailable(pluginName);
|
||||
}
|
||||
|
@ -83,45 +118,30 @@ public class PluginManagerTests extends ElasticsearchIntegrationTest {
|
|||
@Test
|
||||
public void testLocalPluginInstallWithBinAndConfig() throws Exception {
|
||||
String pluginName = "plugin-test";
|
||||
Tuple<Settings, Environment> initialSettings = buildInitialSettings();
|
||||
Environment env = initialSettings.v2();
|
||||
Path binDir = env.homeFile().resolve("bin");
|
||||
if (!Files.exists(binDir)) {
|
||||
Files.createDirectories(binDir);
|
||||
}
|
||||
Path pluginBinDir = binDir.resolve(pluginName);
|
||||
Path configDir = env.configFile();
|
||||
if (!Files.exists(configDir)) {
|
||||
Files.createDirectories(configDir);
|
||||
}
|
||||
Path pluginConfigDir =configDir.resolve(pluginName);
|
||||
try {
|
||||
|
||||
PluginManager pluginManager = pluginManager(getPluginUrlForResource("plugin_with_bin_and_config.zip"), initialSettings);
|
||||
Path pluginConfigDir = env.configFile().resolve(pluginName);
|
||||
String pluginUrl = getPluginUrlForResource("plugin_with_bin_and_config.zip");
|
||||
assertStatusOk("install " + pluginName + " --url " + pluginUrl + " --verbose");
|
||||
|
||||
pluginManager.downloadAndExtract(pluginName);
|
||||
terminal.getTerminalOutput().clear();
|
||||
assertStatusOk("list");
|
||||
assertThat(terminal.getTerminalOutput(), hasItem(containsString(pluginName)));
|
||||
|
||||
Path[] plugins = pluginManager.getListInstalledPlugins();
|
||||
assertDirectoryExists(pluginBinDir);
|
||||
assertDirectoryExists(pluginConfigDir);
|
||||
Path toolFile = pluginBinDir.resolve("tool");
|
||||
assertFileExists(toolFile);
|
||||
|
||||
assertThat(plugins, arrayWithSize(1));
|
||||
assertDirectoryExists(pluginBinDir);
|
||||
assertDirectoryExists(pluginConfigDir);
|
||||
Path toolFile = pluginBinDir.resolve("tool");
|
||||
assertFileExists(toolFile);
|
||||
|
||||
// check that the file is marked executable, without actually checking that we can execute it.
|
||||
PosixFileAttributeView view = Files.getFileAttributeView(toolFile, PosixFileAttributeView.class);
|
||||
// the view might be null, on e.g. windows, there is nothing to check there!
|
||||
if (view != null) {
|
||||
PosixFileAttributes attributes = view.readAttributes();
|
||||
assertTrue("unexpected permissions: " + attributes.permissions(),
|
||||
attributes.permissions().contains(PosixFilePermission.OWNER_EXECUTE));
|
||||
assertTrue("unexpected permissions: " + attributes.permissions(),
|
||||
attributes.permissions().contains(PosixFilePermission.OWNER_READ));
|
||||
}
|
||||
} finally {
|
||||
// we need to clean up the copied dirs
|
||||
IOUtils.rm(pluginBinDir, pluginConfigDir);
|
||||
// check that the file is marked executable, without actually checking that we can execute it.
|
||||
PosixFileAttributeView view = Files.getFileAttributeView(toolFile, PosixFileAttributeView.class);
|
||||
// the view might be null, on e.g. windows, there is nothing to check there!
|
||||
if (view != null) {
|
||||
PosixFileAttributes attributes = view.readAttributes();
|
||||
assertThat(attributes.permissions(), hasItem(PosixFilePermission.OWNER_EXECUTE));
|
||||
assertThat(attributes.permissions(), hasItem(PosixFilePermission.OWNER_READ));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -131,102 +151,76 @@ public class PluginManagerTests extends ElasticsearchIntegrationTest {
|
|||
@Test
|
||||
public void testLocalPluginInstallWithBinAndConfigInAlreadyExistingConfigDir_7890() throws Exception {
|
||||
String pluginName = "plugin-test";
|
||||
Tuple<Settings, Environment> initialSettings = buildInitialSettings();
|
||||
Environment env = initialSettings.v2();
|
||||
Path pluginConfigDir = env.configFile().resolve(pluginName);
|
||||
|
||||
Path configDir = env.configFile();
|
||||
if (!Files.exists(configDir)) {
|
||||
Files.createDirectories(configDir);
|
||||
}
|
||||
Path pluginConfigDir = configDir.resolve(pluginName);
|
||||
assertStatusOk(String.format(Locale.ROOT, "install %s --url %s --verbose", pluginName, getPluginUrlForResource("plugin_with_config_v1.zip")));
|
||||
|
||||
try {
|
||||
PluginManager pluginManager = pluginManager(getPluginUrlForResource("plugin_with_config_v1.zip"), initialSettings);
|
||||
pluginManager.downloadAndExtract(pluginName);
|
||||
/*
|
||||
First time, our plugin contains:
|
||||
- config/test.txt (version1)
|
||||
*/
|
||||
assertFileContent(pluginConfigDir, "test.txt", "version1\n");
|
||||
|
||||
Path[] plugins = pluginManager.getListInstalledPlugins();
|
||||
assertThat(plugins, arrayWithSize(1));
|
||||
// We now remove the plugin
|
||||
assertStatusOk("remove " + pluginName);
|
||||
|
||||
/*
|
||||
First time, our plugin contains:
|
||||
- config/test.txt (version1)
|
||||
*/
|
||||
assertFileContent(pluginConfigDir, "test.txt", "version1\n");
|
||||
// We should still have test.txt
|
||||
assertFileContent(pluginConfigDir, "test.txt", "version1\n");
|
||||
|
||||
// We now remove the plugin
|
||||
pluginManager.removePlugin(pluginName);
|
||||
// We should still have test.txt
|
||||
assertFileContent(pluginConfigDir, "test.txt", "version1\n");
|
||||
// Installing a new plugin version
|
||||
/*
|
||||
Second time, our plugin contains:
|
||||
- config/test.txt (version2)
|
||||
- config/dir/testdir.txt (version1)
|
||||
- config/dir/subdir/testsubdir.txt (version1)
|
||||
*/
|
||||
assertStatusOk(String.format(Locale.ROOT, "install %s --url %s --verbose", pluginName, getPluginUrlForResource("plugin_with_config_v2.zip")));
|
||||
|
||||
// Installing a new plugin version
|
||||
/*
|
||||
Second time, our plugin contains:
|
||||
- config/test.txt (version2)
|
||||
- config/dir/testdir.txt (version1)
|
||||
- config/dir/subdir/testsubdir.txt (version1)
|
||||
*/
|
||||
pluginManager = pluginManager(getPluginUrlForResource("plugin_with_config_v2.zip"), initialSettings);
|
||||
pluginManager.downloadAndExtract(pluginName);
|
||||
assertFileContent(pluginConfigDir, "test.txt", "version1\n");
|
||||
assertFileContent(pluginConfigDir, "test.txt.new", "version2\n");
|
||||
assertFileContent(pluginConfigDir, "dir/testdir.txt", "version1\n");
|
||||
assertFileContent(pluginConfigDir, "dir/subdir/testsubdir.txt", "version1\n");
|
||||
|
||||
assertFileContent(pluginConfigDir, "test.txt", "version1\n");
|
||||
assertFileContent(pluginConfigDir, "test.txt.new", "version2\n");
|
||||
assertFileContent(pluginConfigDir, "dir/testdir.txt", "version1\n");
|
||||
assertFileContent(pluginConfigDir, "dir/subdir/testsubdir.txt", "version1\n");
|
||||
// Removing
|
||||
assertStatusOk("remove " + pluginName);
|
||||
assertFileContent(pluginConfigDir, "test.txt", "version1\n");
|
||||
assertFileContent(pluginConfigDir, "test.txt.new", "version2\n");
|
||||
assertFileContent(pluginConfigDir, "dir/testdir.txt", "version1\n");
|
||||
assertFileContent(pluginConfigDir, "dir/subdir/testsubdir.txt", "version1\n");
|
||||
|
||||
// Removing
|
||||
pluginManager.removePlugin(pluginName);
|
||||
assertFileContent(pluginConfigDir, "test.txt", "version1\n");
|
||||
assertFileContent(pluginConfigDir, "test.txt.new", "version2\n");
|
||||
assertFileContent(pluginConfigDir, "dir/testdir.txt", "version1\n");
|
||||
assertFileContent(pluginConfigDir, "dir/subdir/testsubdir.txt", "version1\n");
|
||||
// Installing a new plugin version
|
||||
/*
|
||||
Third time, our plugin contains:
|
||||
- config/test.txt (version3)
|
||||
- config/test2.txt (version1)
|
||||
- config/dir/testdir.txt (version2)
|
||||
- config/dir/testdir2.txt (version1)
|
||||
- config/dir/subdir/testsubdir.txt (version2)
|
||||
*/
|
||||
assertStatusOk(String.format(Locale.ROOT, "install %s --url %s --verbose", pluginName, getPluginUrlForResource("plugin_with_config_v3.zip")));
|
||||
|
||||
// Installing a new plugin version
|
||||
/*
|
||||
Third time, our plugin contains:
|
||||
- config/test.txt (version3)
|
||||
- config/test2.txt (version1)
|
||||
- config/dir/testdir.txt (version2)
|
||||
- config/dir/testdir2.txt (version1)
|
||||
- config/dir/subdir/testsubdir.txt (version2)
|
||||
*/
|
||||
pluginManager = pluginManager(getPluginUrlForResource("plugin_with_config_v3.zip"), initialSettings);
|
||||
pluginManager.downloadAndExtract(pluginName);
|
||||
|
||||
assertFileContent(pluginConfigDir, "test.txt", "version1\n");
|
||||
assertFileContent(pluginConfigDir, "test2.txt", "version1\n");
|
||||
assertFileContent(pluginConfigDir, "test.txt.new", "version3\n");
|
||||
assertFileContent(pluginConfigDir, "dir/testdir.txt", "version1\n");
|
||||
assertFileContent(pluginConfigDir, "dir/testdir.txt.new", "version2\n");
|
||||
assertFileContent(pluginConfigDir, "dir/testdir2.txt", "version1\n");
|
||||
assertFileContent(pluginConfigDir, "dir/subdir/testsubdir.txt", "version1\n");
|
||||
assertFileContent(pluginConfigDir, "dir/subdir/testsubdir.txt.new", "version2\n");
|
||||
} finally {
|
||||
// we need to clean up the copied dirs
|
||||
IOUtils.rm(pluginConfigDir);
|
||||
}
|
||||
assertFileContent(pluginConfigDir, "test.txt", "version1\n");
|
||||
assertFileContent(pluginConfigDir, "test2.txt", "version1\n");
|
||||
assertFileContent(pluginConfigDir, "test.txt.new", "version3\n");
|
||||
assertFileContent(pluginConfigDir, "dir/testdir.txt", "version1\n");
|
||||
assertFileContent(pluginConfigDir, "dir/testdir.txt.new", "version2\n");
|
||||
assertFileContent(pluginConfigDir, "dir/testdir2.txt", "version1\n");
|
||||
assertFileContent(pluginConfigDir, "dir/subdir/testsubdir.txt", "version1\n");
|
||||
assertFileContent(pluginConfigDir, "dir/subdir/testsubdir.txt.new", "version2\n");
|
||||
}
|
||||
|
||||
// For #7152
|
||||
@Test
|
||||
public void testLocalPluginInstallWithBinOnly_7152() throws Exception {
|
||||
String pluginName = "plugin-test";
|
||||
Tuple<Settings, Environment> initialSettings = buildInitialSettings();
|
||||
Environment env = initialSettings.v2();
|
||||
Path binDir = env.homeFile().resolve("bin");
|
||||
if (!Files.exists(binDir)) {
|
||||
Files.createDirectories(binDir);
|
||||
}
|
||||
Path pluginBinDir = binDir.resolve(pluginName);
|
||||
try {
|
||||
PluginManager pluginManager = pluginManager(getPluginUrlForResource("plugin_with_bin_only.zip"), initialSettings);
|
||||
pluginManager.downloadAndExtract(pluginName);
|
||||
Path[] plugins = pluginManager.getListInstalledPlugins();
|
||||
assertThat(plugins.length, is(1));
|
||||
assertDirectoryExists(pluginBinDir);
|
||||
} finally {
|
||||
// we need to clean up the copied dirs
|
||||
IOUtils.rm(pluginBinDir);
|
||||
}
|
||||
|
||||
assertStatusOk(String.format(Locale.ROOT, "install %s --url %s --verbose", pluginName, getPluginUrlForResource("plugin_with_bin_only.zip")));
|
||||
assertThatPluginIsListed(pluginName);
|
||||
assertDirectoryExists(pluginBinDir);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -234,8 +228,7 @@ public class PluginManagerTests extends ElasticsearchIntegrationTest {
|
|||
//When we have only a folder in top-level (no files either) but it's called _site, we make it work
|
||||
//we can either remove the folder while extracting and then re-add it manually or just leave it as it is
|
||||
String pluginName = "plugin-test";
|
||||
Tuple<Settings, Environment> initialSettings = buildInitialSettings();
|
||||
downloadAndExtract(pluginName, initialSettings, getPluginUrlForResource("plugin_folder_site.zip"));
|
||||
assertStatusOk(String.format(Locale.ROOT, "install %s --url %s --verbose", pluginName, getPluginUrlForResource("plugin_folder_site.zip")));
|
||||
|
||||
internalCluster().startNode(initialSettings.v1());
|
||||
|
||||
|
@ -247,8 +240,7 @@ public class PluginManagerTests extends ElasticsearchIntegrationTest {
|
|||
public void testLocalPluginWithoutFolders() throws Exception {
|
||||
//When we don't have folders at all in the top-level, but only files, we don't modify anything
|
||||
String pluginName = "plugin-test";
|
||||
Tuple<Settings, Environment> initialSettings = buildInitialSettings();
|
||||
downloadAndExtract(pluginName, initialSettings, getPluginUrlForResource("plugin_without_folders.zip"));
|
||||
assertStatusOk(String.format(Locale.ROOT, "install %s --url %s --verbose", pluginName, getPluginUrlForResource("plugin_without_folders.zip")));
|
||||
|
||||
internalCluster().startNode(initialSettings.v1());
|
||||
|
||||
|
@ -260,8 +252,7 @@ public class PluginManagerTests extends ElasticsearchIntegrationTest {
|
|||
public void testLocalPluginFolderAndFile() throws Exception {
|
||||
//When we have a single top-level folder but also files in the top-level, we don't modify anything
|
||||
String pluginName = "plugin-test";
|
||||
Tuple<Settings, Environment> initialSettings = buildInitialSettings();
|
||||
downloadAndExtract(pluginName, initialSettings, getPluginUrlForResource("plugin_folder_file.zip"));
|
||||
assertStatusOk(String.format(Locale.ROOT, "install %s --url %s --verbose", pluginName, getPluginUrlForResource("plugin_folder_file.zip")));
|
||||
|
||||
internalCluster().startNode(initialSettings.v1());
|
||||
|
||||
|
@ -269,37 +260,13 @@ public class PluginManagerTests extends ElasticsearchIntegrationTest {
|
|||
assertPluginAvailable(pluginName);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testSitePluginWithSourceThrows() throws Exception {
|
||||
@Test
|
||||
public void testSitePluginWithSourceDoesNotInstall() throws Exception {
|
||||
String pluginName = "plugin-with-source";
|
||||
downloadAndExtract(pluginName, buildInitialSettings(), getPluginUrlForResource("plugin_with_sourcefiles.zip"));
|
||||
}
|
||||
|
||||
private PluginManager pluginManager(String pluginUrl) throws IOException {
|
||||
return pluginManager(pluginUrl, buildInitialSettings());
|
||||
}
|
||||
|
||||
private Tuple<Settings, Environment> buildInitialSettings() throws IOException {
|
||||
Settings settings = Settings.settingsBuilder()
|
||||
.put("discovery.zen.ping.multicast.enabled", false)
|
||||
.put("http.enabled", true)
|
||||
.put("path.home", createTempDir()).build();
|
||||
return InternalSettingsPreparer.prepareSettings(settings, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* We build a plugin manager instance which wait only for 30 seconds before
|
||||
* raising an ElasticsearchTimeoutException
|
||||
*/
|
||||
private PluginManager pluginManager(String pluginUrl, Tuple<Settings, Environment> initialSettings) throws IOException {
|
||||
if (!Files.exists(initialSettings.v2().pluginsFile())) {
|
||||
Files.createDirectories(initialSettings.v2().pluginsFile());
|
||||
}
|
||||
return new PluginManager(initialSettings.v2(), pluginUrl, PluginManager.OutputMode.VERBOSE, TimeValue.timeValueSeconds(30));
|
||||
}
|
||||
|
||||
private void downloadAndExtract(String pluginName, Tuple<Settings, Environment> initialSettings, String pluginUrl) throws IOException {
|
||||
pluginManager(pluginUrl, initialSettings).downloadAndExtract(pluginName);
|
||||
String cmd = String.format(Locale.ROOT, "install %s --url %s --verbose", pluginName, getPluginUrlForResource("plugin_with_sourcefiles.zip"));
|
||||
int status = new PluginManagerCliParser(terminal).execute(args(cmd));
|
||||
assertThat(status, is(USAGE.status()));
|
||||
assertThat(terminal.getTerminalOutput(), hasItem(containsString("Plugin installation assumed to be site plugin, but contains source code, aborting installation")));
|
||||
}
|
||||
|
||||
private void assertPluginLoaded(String pluginName) {
|
||||
|
@ -352,61 +319,44 @@ public class PluginManagerTests extends ElasticsearchIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testListInstalledEmpty() throws IOException {
|
||||
Path[] plugins = pluginManager(null).getListInstalledPlugins();
|
||||
assertThat(plugins, notNullValue());
|
||||
assertThat(plugins.length, is(0));
|
||||
assertStatusOk("list");
|
||||
assertThat(terminal.getTerminalOutput(), hasItem(containsString("No plugin detected")));
|
||||
}
|
||||
|
||||
@Test(expected = IOException.class)
|
||||
public void testInstallPluginNull() throws IOException {
|
||||
pluginManager(null).downloadAndExtract("plugin-test");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testInstallPlugin() throws IOException {
|
||||
PluginManager pluginManager = pluginManager(getPluginUrlForResource("plugin_with_classfile.zip"));
|
||||
|
||||
pluginManager.downloadAndExtract("plugin-classfile");
|
||||
Path[] plugins = pluginManager.getListInstalledPlugins();
|
||||
assertThat(plugins, notNullValue());
|
||||
assertThat(plugins.length, is(1));
|
||||
String pluginName = "plugin-classfile";
|
||||
assertStatusOk(String.format(Locale.ROOT, "install %s --url %s --verbose", pluginName, getPluginUrlForResource("plugin_with_classfile.zip")));
|
||||
assertThatPluginIsListed("plugin-classfile");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInstallSitePlugin() throws IOException {
|
||||
Tuple<Settings, Environment> initialSettings = buildInitialSettings();
|
||||
PluginManager pluginManager = pluginManager(getPluginUrlForResource("plugin_without_folders.zip"), initialSettings);
|
||||
|
||||
pluginManager.downloadAndExtract("plugin-site");
|
||||
Path[] plugins = pluginManager.getListInstalledPlugins();
|
||||
assertThat(plugins, notNullValue());
|
||||
assertThat(plugins.length, is(1));
|
||||
|
||||
String pluginName = "plugin-site";
|
||||
assertStatusOk(String.format(Locale.ROOT, "install %s --url %s --verbose", pluginName, getPluginUrlForResource("plugin_without_folders.zip")));
|
||||
assertThatPluginIsListed(pluginName);
|
||||
// We want to check that Plugin Manager moves content to _site
|
||||
assertFileExists(initialSettings.v2().pluginsFile().resolve("plugin-site/_site"));
|
||||
}
|
||||
|
||||
|
||||
private void singlePluginInstallAndRemove(String pluginShortName, String pluginCoordinates) throws IOException {
|
||||
logger.info("--> trying to download and install [{}]", pluginShortName);
|
||||
PluginManager pluginManager = pluginManager(pluginCoordinates);
|
||||
try {
|
||||
pluginManager.downloadAndExtract(pluginShortName);
|
||||
Path[] plugins = pluginManager.getListInstalledPlugins();
|
||||
assertThat(plugins, notNullValue());
|
||||
assertThat(plugins.length, is(1));
|
||||
|
||||
// We remove it
|
||||
pluginManager.removePlugin(pluginShortName);
|
||||
plugins = pluginManager.getListInstalledPlugins();
|
||||
assertThat(plugins, notNullValue());
|
||||
assertThat(plugins.length, is(0));
|
||||
} catch (IOException e) {
|
||||
logger.warn("--> IOException raised while downloading plugin [{}]. Skipping test.", e, pluginShortName);
|
||||
} catch (ElasticsearchTimeoutException e) {
|
||||
logger.warn("--> timeout exception raised while downloading plugin [{}]. Skipping test.", pluginShortName);
|
||||
private void singlePluginInstallAndRemove(String pluginDescriptor, String pluginName, String pluginCoordinates) throws IOException {
|
||||
logger.info("--> trying to download and install [{}]", pluginDescriptor);
|
||||
if (pluginCoordinates == null) {
|
||||
assertStatusOk(String.format(Locale.ROOT, "install %s --verbose", pluginDescriptor));
|
||||
} else {
|
||||
assertStatusOk(String.format(Locale.ROOT, "install %s --url %s --verbose", pluginDescriptor, pluginCoordinates));
|
||||
}
|
||||
assertThatPluginIsListed(pluginName);
|
||||
|
||||
terminal.getTerminalOutput().clear();
|
||||
assertStatusOk("remove " + pluginDescriptor);
|
||||
assertThat(terminal.getTerminalOutput(), hasItem(containsString("Removing " + pluginDescriptor)));
|
||||
|
||||
// not listed anymore
|
||||
terminal.getTerminalOutput().clear();
|
||||
assertStatusOk("list");
|
||||
assertThat(terminal.getTerminalOutput(), not(hasItem(containsString(pluginName))));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -420,7 +370,7 @@ public class PluginManagerTests extends ElasticsearchIntegrationTest {
|
|||
@AwaitsFix(bugUrl = "fails with jar hell failures - http://build-us-00.elastic.co/job/es_core_master_oracle_6/519/testReport/")
|
||||
public void testInstallPluginWithElasticsearchDownloadService() throws IOException {
|
||||
assumeTrue("download.elastic.co is accessible", isDownloadServiceWorking("download.elastic.co", 80, "/elasticsearch/ci-test.txt"));
|
||||
singlePluginInstallAndRemove("elasticsearch/elasticsearch-transport-thrift/2.4.0", null);
|
||||
singlePluginInstallAndRemove("elasticsearch/elasticsearch-transport-thrift/2.4.0", "elasticsearch-transport-thrift", null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -435,7 +385,7 @@ public class PluginManagerTests extends ElasticsearchIntegrationTest {
|
|||
public void testInstallPluginWithMavenCentral() throws IOException {
|
||||
assumeTrue("search.maven.org is accessible", isDownloadServiceWorking("search.maven.org", 80, "/"));
|
||||
assumeTrue("repo1.maven.org is accessible", isDownloadServiceWorking("repo1.maven.org", 443, "/maven2/org/elasticsearch/elasticsearch-transport-thrift/2.4.0/elasticsearch-transport-thrift-2.4.0.pom"));
|
||||
singlePluginInstallAndRemove("org.elasticsearch/elasticsearch-transport-thrift/2.4.0", null);
|
||||
singlePluginInstallAndRemove("org.elasticsearch/elasticsearch-transport-thrift/2.4.0", "elasticsearch-transport-thrift", null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -448,7 +398,7 @@ public class PluginManagerTests extends ElasticsearchIntegrationTest {
|
|||
@Network
|
||||
public void testInstallPluginWithGithub() throws IOException {
|
||||
assumeTrue("github.com is accessible", isDownloadServiceWorking("github.com", 443, "/"));
|
||||
singlePluginInstallAndRemove("elasticsearch/kibana", null);
|
||||
singlePluginInstallAndRemove("elasticsearch/kibana", "kibana", null);
|
||||
}
|
||||
|
||||
private boolean isDownloadServiceWorking(String host, int port, String resource) {
|
||||
|
@ -469,48 +419,38 @@ public class PluginManagerTests extends ElasticsearchIntegrationTest {
|
|||
@Test
|
||||
public void testRemovePlugin() throws Exception {
|
||||
// We want to remove plugin with plugin short name
|
||||
singlePluginInstallAndRemove("plugintest", getPluginUrlForResource("plugin_without_folders.zip"));
|
||||
singlePluginInstallAndRemove("plugintest", "plugintest", getPluginUrlForResource("plugin_without_folders.zip"));
|
||||
|
||||
// We want to remove plugin with groupid/artifactid/version form
|
||||
singlePluginInstallAndRemove("groupid/plugintest/1.0.0", getPluginUrlForResource("plugin_without_folders.zip"));
|
||||
singlePluginInstallAndRemove("groupid/plugintest/1.0.0", "plugintest", getPluginUrlForResource("plugin_without_folders.zip"));
|
||||
|
||||
// We want to remove plugin with groupid/artifactid form
|
||||
singlePluginInstallAndRemove("groupid/plugintest", getPluginUrlForResource("plugin_without_folders.zip"));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testRemovePlugin_NullName_ThrowsException() throws IOException {
|
||||
pluginManager(getPluginUrlForResource("plugin_single_folder.zip")).removePlugin(null);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testRemovePluginWithURLForm() throws Exception {
|
||||
PluginManager pluginManager = pluginManager(null);
|
||||
pluginManager.removePlugin("file://whatever");
|
||||
singlePluginInstallAndRemove("groupid/plugintest", "plugintest", getPluginUrlForResource("plugin_without_folders.zip"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForbiddenPluginName_ThrowsException() throws IOException {
|
||||
runTestWithForbiddenName(null);
|
||||
runTestWithForbiddenName("");
|
||||
runTestWithForbiddenName("elasticsearch");
|
||||
runTestWithForbiddenName("elasticsearch.bat");
|
||||
runTestWithForbiddenName("elasticsearch.in.sh");
|
||||
runTestWithForbiddenName("plugin");
|
||||
runTestWithForbiddenName("plugin.bat");
|
||||
runTestWithForbiddenName("service.bat");
|
||||
runTestWithForbiddenName("ELASTICSEARCH");
|
||||
runTestWithForbiddenName("ELASTICSEARCH.IN.SH");
|
||||
public void testRemovePlugin_NullName_ThrowsException() throws IOException {
|
||||
int status = new PluginManagerCliParser(terminal).execute(args("remove "));
|
||||
assertThat("Terminal output was: " + terminal.getTerminalOutput(), status, is(USAGE.status()));
|
||||
}
|
||||
|
||||
private void runTestWithForbiddenName(String name) throws IOException {
|
||||
try {
|
||||
pluginManager(null).removePlugin(name);
|
||||
fail("this plugin name [" + name +
|
||||
"] should not be allowed");
|
||||
} catch (IllegalArgumentException e) {
|
||||
// We expect that error
|
||||
}
|
||||
@Test
|
||||
public void testRemovePluginWithURLForm() throws Exception {
|
||||
int status = new PluginManagerCliParser(terminal).execute(args("remove file://whatever"));
|
||||
assertThat(terminal.getTerminalOutput(), hasItem(containsString("Illegal plugin name")));
|
||||
assertThat("Terminal output was: " + terminal.getTerminalOutput(), status, is(USAGE.status()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForbiddenPluginNames() throws IOException {
|
||||
assertStatus("remove elasticsearch", USAGE);
|
||||
assertStatus("remove elasticsearch.bat", USAGE);
|
||||
assertStatus("remove elasticsearch.in.sh", USAGE);
|
||||
assertStatus("remove plugin", USAGE);
|
||||
assertStatus("remove plugin.bat", USAGE);
|
||||
assertStatus("remove service.bat", USAGE);
|
||||
assertStatus("remove ELASTICSEARCH", USAGE);
|
||||
assertStatus("remove ELASTICSEARCH.IN.SH", USAGE);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -535,6 +475,33 @@ public class PluginManagerTests extends ElasticsearchIntegrationTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHelpWorks() throws IOException {
|
||||
assertStatusOk("--help");
|
||||
assertHelp("/org/elasticsearch/plugins/plugin.help");
|
||||
|
||||
terminal.getTerminalOutput().clear();
|
||||
assertStatusOk("install -h");
|
||||
assertHelp("/org/elasticsearch/plugins/plugin-install.help");
|
||||
for (String plugin : PluginManager.OFFICIAL_PLUGINS) {
|
||||
assertThat(terminal.getTerminalOutput(), hasItem(containsString(plugin)));
|
||||
}
|
||||
|
||||
terminal.getTerminalOutput().clear();
|
||||
assertStatusOk("remove --help");
|
||||
assertHelp("/org/elasticsearch/plugins/plugin-remove.help");
|
||||
|
||||
terminal.getTerminalOutput().clear();
|
||||
assertStatusOk("list -h");
|
||||
assertHelp("/org/elasticsearch/plugins/plugin-list.help");
|
||||
}
|
||||
|
||||
private void assertHelp(String classPath) throws IOException {
|
||||
String expectedDocs = Streams.copyToStringFromClasspath(classPath);
|
||||
String returnedDocs = Joiner.on("").join(terminal.getTerminalOutput());
|
||||
assertThat(returnedDocs.trim(), is(expectedDocs.trim()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a URL string that represents the resource with the given {@code resourceName}.
|
||||
* @param resourceName The resource name relative to {@link PluginManagerTests}.
|
||||
|
@ -546,4 +513,28 @@ public class PluginManagerTests extends ElasticsearchIntegrationTest {
|
|||
|
||||
return "file://" + uri.getPath();
|
||||
}
|
||||
|
||||
private Tuple<Settings, Environment> buildInitialSettings() throws IOException {
|
||||
Settings settings = settingsBuilder()
|
||||
.put("discovery.zen.ping.multicast.enabled", false)
|
||||
.put("http.enabled", true)
|
||||
.put("path.home", createTempDir()).build();
|
||||
return InternalSettingsPreparer.prepareSettings(settings, false);
|
||||
}
|
||||
|
||||
private void assertStatusOk(String command) {
|
||||
assertStatus(command, CliTool.ExitStatus.OK);
|
||||
}
|
||||
|
||||
private void assertStatus(String command, CliTool.ExitStatus exitStatus) {
|
||||
int status = new PluginManagerCliParser(terminal).execute(args(command));
|
||||
assertThat("Terminal output was: " + terminal.getTerminalOutput(), status, is(exitStatus.status()));
|
||||
}
|
||||
|
||||
private void assertThatPluginIsListed(String pluginName) {
|
||||
terminal.getTerminalOutput().clear();
|
||||
assertStatusOk("list");
|
||||
String message = String.format(Locale.ROOT, "Terminal output was: %s", terminal.getTerminalOutput());
|
||||
assertThat(message, terminal.getTerminalOutput(), hasItem(containsString(pluginName)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ Installing plugins typically take the following form:
|
|||
|
||||
[source,sh]
|
||||
-----------------------------------
|
||||
bin/plugin --install plugin_name
|
||||
bin/plugin install plugin_name
|
||||
-----------------------------------
|
||||
|
||||
The plugin will be automatically downloaded in this case from `download.elastic.co` download service using the
|
||||
|
@ -30,7 +30,7 @@ For older version of elasticsearch (prior to 2.0.0) or community plugins, you wo
|
|||
|
||||
[source,sh]
|
||||
-----------------------------------
|
||||
bin/plugin --install <org>/<user/component>/<version>
|
||||
bin/plugin install <org>/<user/component>/<version>
|
||||
-----------------------------------
|
||||
|
||||
The plugins will be automatically downloaded in this case from `download.elastic.co` (for older plugins),
|
||||
|
@ -45,7 +45,7 @@ for example:
|
|||
|
||||
[source,sh]
|
||||
-----------------------------------
|
||||
bin/plugin --url file:///path/to/plugin --install plugin-name
|
||||
bin/plugin install plugin-name --url file:///path/to/plugin
|
||||
-----------------------------------
|
||||
|
||||
|
||||
|
@ -70,8 +70,8 @@ running:
|
|||
|
||||
[source,js]
|
||||
--------------------------------------------------
|
||||
bin/plugin --install mobz/elasticsearch-head
|
||||
bin/plugin --install lukas-vlcek/bigdesk
|
||||
bin/plugin install mobz/elasticsearch-head
|
||||
bin/plugin install lukas-vlcek/bigdesk
|
||||
--------------------------------------------------
|
||||
|
||||
Will install both of those site plugins, with `elasticsearch-head`
|
||||
|
@ -108,7 +108,7 @@ Removing plugins typically take the following form:
|
|||
|
||||
[source,sh]
|
||||
-----------------------------------
|
||||
plugin --remove <pluginname>
|
||||
plugin remove <pluginname>
|
||||
-----------------------------------
|
||||
|
||||
[float]
|
||||
|
@ -126,8 +126,8 @@ Note that exit codes could be:
|
|||
|
||||
[source,sh]
|
||||
-----------------------------------
|
||||
bin/plugin --install mobz/elasticsearch-head --verbose
|
||||
plugin --remove head --silent
|
||||
bin/plugin install mobz/elasticsearch-head --verbose
|
||||
plugin remove head --silent
|
||||
-----------------------------------
|
||||
|
||||
[float]
|
||||
|
@ -140,33 +140,25 @@ different values:
|
|||
[source,sh]
|
||||
-----------------------------------
|
||||
# Wait for 30 seconds before failing
|
||||
bin/plugin --install mobz/elasticsearch-head --timeout 30s
|
||||
bin/plugin install mobz/elasticsearch-head --timeout 30s
|
||||
|
||||
# Wait for 1 minute before failing
|
||||
bin/plugin --install mobz/elasticsearch-head --timeout 1m
|
||||
bin/plugin install mobz/elasticsearch-head --timeout 1m
|
||||
|
||||
# Wait forever (default)
|
||||
bin/plugin --install mobz/elasticsearch-head --timeout 0
|
||||
bin/plugin install mobz/elasticsearch-head --timeout 0
|
||||
-----------------------------------
|
||||
|
||||
[float]
|
||||
==== Proxy settings
|
||||
|
||||
|
||||
To install a plugin via a proxy, you can pass the proxy details using the environment variables `proxyHost` and `proxyPort`.
|
||||
|
||||
On Linux and Mac, here is an example of setting it:
|
||||
|
||||
[source,sh]
|
||||
-----------------------------------
|
||||
bin/plugin -DproxyHost=host_name -DproxyPort=port_number --install mobz/elasticsearch-head
|
||||
-----------------------------------
|
||||
|
||||
On Windows, here is an example of setting it:
|
||||
|
||||
[source,sh]
|
||||
-----------------------------------
|
||||
set JAVA_OPTS="-DproxyHost=host_name -DproxyPort=port_number"
|
||||
bin/plugin --install mobz/elasticsearch-head
|
||||
bin/plugin install mobz/elasticsearch-head
|
||||
-----------------------------------
|
||||
|
||||
[float]
|
||||
|
|
|
@ -29,7 +29,7 @@ To build a `SNAPSHOT` version, you need to build it with Maven:
|
|||
|
||||
```bash
|
||||
mvn clean install
|
||||
plugin --install analysis-icu \
|
||||
plugin install analysis-icu \
|
||||
--url file:target/releases/elasticsearch-analysis-icu-X.X.X-SNAPSHOT.zip
|
||||
```
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ To build a `SNAPSHOT` version, you need to build it with Maven:
|
|||
|
||||
```bash
|
||||
mvn clean install
|
||||
plugin --install analysis-kuromoji \
|
||||
plugin install analysis-kuromoji \
|
||||
--url file:target/releases/elasticsearch-analysis-kuromoji-X.X.X-SNAPSHOT.zip
|
||||
```
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ To build a `SNAPSHOT` version, you need to build it with Maven:
|
|||
|
||||
```bash
|
||||
mvn clean install
|
||||
plugin --install analysis-phonetic \
|
||||
plugin install analysis-phonetic \
|
||||
--url file:target/releases/elasticsearch-analysis-phonetic-X.X.X-SNAPSHOT.zip
|
||||
```
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ To build a `SNAPSHOT` version, you need to build it with Maven:
|
|||
|
||||
```bash
|
||||
mvn clean install
|
||||
plugin --install analysis-smartcn \
|
||||
plugin install analysis-smartcn \
|
||||
--url file:target/releases/elasticsearch-analysis-smartcn-X.X.X-SNAPSHOT.zip
|
||||
```
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ To build a `SNAPSHOT` version, you need to build it with Maven:
|
|||
|
||||
```bash
|
||||
mvn clean install
|
||||
plugin --install analysis-stempel \
|
||||
plugin install analysis-stempel \
|
||||
--url file:target/releases/elasticsearch-analysis-stempel-X.X.X-SNAPSHOT.zip
|
||||
```
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ To build a `SNAPSHOT` version, you need to build it with Maven:
|
|||
|
||||
```bash
|
||||
mvn clean install
|
||||
plugin --install cloud-aws \
|
||||
plugin install cloud-aws \
|
||||
--url file:target/releases/elasticsearch-cloud-aws-X.X.X-SNAPSHOT.zip
|
||||
```
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ To build a `SNAPSHOT` version, you need to build it with Maven:
|
|||
|
||||
```bash
|
||||
mvn clean install
|
||||
plugin --install cloud-azure \
|
||||
plugin install cloud-azure \
|
||||
--url file:target/releases/elasticsearch-cloud-azure-X.X.X-SNAPSHOT.zip
|
||||
```
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ To build a `SNAPSHOT` version, you need to build it with Maven:
|
|||
|
||||
```bash
|
||||
mvn clean install
|
||||
plugin --install cloud-gce \
|
||||
plugin install cloud-gce \
|
||||
--url file:target/releases/elasticsearch-cloud-gce-X.X.X-SNAPSHOT.zip
|
||||
```
|
||||
|
||||
|
@ -148,7 +148,7 @@ Install the plugin:
|
|||
|
||||
```sh
|
||||
# Use Plugin Manager to install it
|
||||
sudo /usr/share/elasticsearch/bin/plugin --install elasticsearch/elasticsearch-cloud-gce/2.2.0
|
||||
sudo /usr/share/elasticsearch/bin/plugin install elasticsearch/elasticsearch-cloud-gce/2.2.0
|
||||
|
||||
# Configure it:
|
||||
sudo vi /etc/elasticsearch/elasticsearch.yml
|
||||
|
|
|
@ -27,7 +27,7 @@ To build a `SNAPSHOT` version, you need to build it with Maven:
|
|||
|
||||
```bash
|
||||
mvn clean install
|
||||
plugin --install lang-javascript \
|
||||
plugin install lang-javascript \
|
||||
--url file:target/releases/elasticsearch-lang-javascript-X.X.X-SNAPSHOT.zip
|
||||
```
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ To build a `SNAPSHOT` version, you need to build it with Maven:
|
|||
|
||||
```bash
|
||||
mvn clean install
|
||||
plugin --install lang-python \
|
||||
plugin install lang-python \
|
||||
--url file:target/releases/elasticsearch-lang-python-X.X.X-SNAPSHOT.zip
|
||||
```
|
||||
|
||||
|
|
Loading…
Reference in New Issue