Plugins: Add 'name' property to plugin descriptor file to determine plugin name
At the moment, when installing from an url, a user provides the plugin name on the command line like: * bin/plugin install [plugin-name] --url [url] This can lead to problems when picking an already existing name from another plugin, and can potentially overwrite plugins already installed with that name. This, this PR introduces a mandatory `name` property to the plugin descriptor file which replaces the name formerly provided by the user. With the addition of the `name` property to the plugin descriptor file, the user does not need to specify the plugin name any longer when installing from a file or url. Because of this, all arguments to `plugin install` command are now either treated as a symbolic name, a URL or a file without the need to specify this with an explicit option. The new syntax for `plugin install` is now: bin/plugin install [name or url] * downloads official plugin bin/plugin install analysis-kuromoji * downloads github plugin bin/plugin install lmenezes/elasticsearch-kopf * install from URL or file bin/plugin install http://link.to/foo.zip bin/plugin install file:/path/to/foo.zip If the argument does not parse to a valid URL, it is assumed to be a name and the download location is resolved like before. Regardless of the source location of the plugin, it is extracted to a temporary directory and the `name` property from the descriptor file is used to determine the final install location. Relates to #12715
This commit is contained in:
parent
66b0e7a6e1
commit
8454d49552
|
@ -52,7 +52,7 @@ public class PluginInfo implements Streamable, ToXContent {
|
|||
private String description;
|
||||
private boolean site;
|
||||
private String version;
|
||||
|
||||
|
||||
private boolean jvm;
|
||||
private String classname;
|
||||
private boolean isolated;
|
||||
|
@ -86,7 +86,11 @@ public class PluginInfo implements Streamable, ToXContent {
|
|||
try (InputStream stream = Files.newInputStream(descriptor)) {
|
||||
props.load(stream);
|
||||
}
|
||||
String name = dir.getFileName().toString();
|
||||
String name = props.getProperty("name");
|
||||
if (name == null || name.isEmpty()) {
|
||||
throw new IllegalArgumentException("Property [name] is missing in [" + descriptor + "]");
|
||||
}
|
||||
PluginManager.checkForForbiddenName(name);
|
||||
String description = props.getProperty("description");
|
||||
if (description == null) {
|
||||
throw new IllegalArgumentException("Property [description] is missing for plugin [" + name + "]");
|
||||
|
@ -95,6 +99,7 @@ public class PluginInfo implements Streamable, ToXContent {
|
|||
if (version == null) {
|
||||
throw new IllegalArgumentException("Property [version] is missing for plugin [" + name + "]");
|
||||
}
|
||||
|
||||
boolean jvm = Boolean.parseBoolean(props.getProperty("jvm"));
|
||||
boolean site = Boolean.parseBoolean(props.getProperty("site"));
|
||||
if (jvm == false && site == false) {
|
||||
|
@ -122,7 +127,7 @@ public class PluginInfo implements Streamable, ToXContent {
|
|||
throw new IllegalArgumentException("Property [classname] is missing for jvm plugin [" + name + "]");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (site) {
|
||||
if (!Files.exists(dir.resolve("_site"))) {
|
||||
throw new IllegalArgumentException("Plugin [" + name + "] is a site plugin but has no '_site/' directory");
|
||||
|
@ -159,14 +164,14 @@ public class PluginInfo implements Streamable, ToXContent {
|
|||
public boolean isJvm() {
|
||||
return jvm;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return true if jvm plugin has isolated classloader
|
||||
*/
|
||||
public boolean isIsolated() {
|
||||
return isolated;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return jvm plugin's classname
|
||||
*/
|
||||
|
|
|
@ -91,11 +91,11 @@ public class PluginManager {
|
|||
).build();
|
||||
|
||||
private final Environment environment;
|
||||
private String url;
|
||||
private URL url;
|
||||
private OutputMode outputMode;
|
||||
private TimeValue timeout;
|
||||
|
||||
public PluginManager(Environment environment, String url, OutputMode outputMode, TimeValue timeout) {
|
||||
public PluginManager(Environment environment, URL url, OutputMode outputMode, TimeValue timeout) {
|
||||
this.environment = environment;
|
||||
this.url = url;
|
||||
this.outputMode = outputMode;
|
||||
|
@ -103,8 +103,8 @@ public class PluginManager {
|
|||
}
|
||||
|
||||
public void downloadAndExtract(String name, Terminal terminal) throws IOException {
|
||||
if (name == null) {
|
||||
throw new IllegalArgumentException("plugin name must be supplied with install [name].");
|
||||
if (name == null && url == null) {
|
||||
throw new IllegalArgumentException("plugin name or url must be supplied with install.");
|
||||
}
|
||||
|
||||
if (!Files.exists(environment.pluginsFile())) {
|
||||
|
@ -116,8 +116,14 @@ public class PluginManager {
|
|||
throw new IOException("plugin directory " + environment.pluginsFile() + " is read only");
|
||||
}
|
||||
|
||||
PluginHandle pluginHandle = PluginHandle.parse(name);
|
||||
checkForForbiddenName(pluginHandle.name);
|
||||
PluginHandle pluginHandle;
|
||||
if (name != null) {
|
||||
pluginHandle = PluginHandle.parse(name);
|
||||
checkForForbiddenName(pluginHandle.name);
|
||||
} else {
|
||||
// if we have no name but url, use temporary name that will be overwritten later
|
||||
pluginHandle = new PluginHandle("temp_name" + new Random().nextInt(), null, null);
|
||||
}
|
||||
|
||||
Path pluginFile = download(pluginHandle, terminal);
|
||||
extract(pluginHandle, terminal, pluginFile);
|
||||
|
@ -138,7 +144,7 @@ public class PluginManager {
|
|||
|
||||
// first, try directly from the URL provided
|
||||
if (url != null) {
|
||||
URL pluginUrl = new URL(url);
|
||||
URL pluginUrl = url;
|
||||
boolean isSecureProcotol = "https".equalsIgnoreCase(pluginUrl.getProtocol());
|
||||
boolean isAuthInfoSet = !Strings.isNullOrEmpty(pluginUrl.getUserInfo());
|
||||
if (isAuthInfoSet && !isSecureProcotol) {
|
||||
|
@ -204,14 +210,10 @@ public class PluginManager {
|
|||
}
|
||||
|
||||
private void extract(PluginHandle pluginHandle, Terminal terminal, Path pluginFile) throws IOException {
|
||||
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 " + pluginHandle.name + "' command");
|
||||
}
|
||||
|
||||
// unzip plugin to a staging temp dir, named for the plugin
|
||||
Path tmp = Files.createTempDirectory(environment.tmpFile(), null);
|
||||
Path root = tmp.resolve(pluginHandle.name);
|
||||
Path root = tmp.resolve(pluginHandle.name);
|
||||
unzipPlugin(pluginFile, root);
|
||||
|
||||
// find the actual root (in case its unzipped with extra directory wrapping)
|
||||
|
@ -226,6 +228,13 @@ public class PluginManager {
|
|||
jarHellCheck(root, info.isIsolated());
|
||||
}
|
||||
|
||||
// update name in handle based on 'name' property found in descriptor file
|
||||
pluginHandle = new PluginHandle(info.getName(), pluginHandle.version, pluginHandle.user);
|
||||
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 " + pluginHandle.name + "' command");
|
||||
}
|
||||
|
||||
// install plugin
|
||||
FileSystemUtils.copyDirectoryRecursively(root, extractLocation);
|
||||
terminal.println("Installed %s into %s", pluginHandle.name, extractLocation.toAbsolutePath());
|
||||
|
@ -334,7 +343,7 @@ public class PluginManager {
|
|||
|
||||
private void unzipPlugin(Path zip, Path target) throws IOException {
|
||||
Files.createDirectories(target);
|
||||
|
||||
|
||||
try (ZipInputStream zipInput = new ZipInputStream(Files.newInputStream(zip))) {
|
||||
ZipEntry entry;
|
||||
byte[] buffer = new byte[8192];
|
||||
|
@ -395,7 +404,7 @@ public class PluginManager {
|
|||
}
|
||||
}
|
||||
|
||||
private static void checkForForbiddenName(String name) {
|
||||
static void checkForForbiddenName(String name) {
|
||||
if (!hasLength(name) || BLACKLIST.contains(name.toLowerCase(Locale.ROOT))) {
|
||||
throw new IllegalArgumentException("Illegal plugin name: " + name);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
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;
|
||||
|
@ -32,7 +33,8 @@ import org.elasticsearch.env.Environment;
|
|||
import org.elasticsearch.node.internal.InternalSettingsPreparer;
|
||||
import org.elasticsearch.plugins.PluginManager.OutputMode;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Locale;
|
||||
|
||||
import static org.elasticsearch.common.cli.CliToolConfig.Builder.cmd;
|
||||
|
@ -166,19 +168,29 @@ public class PluginManagerCliParser extends CliTool {
|
|||
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();
|
||||
|
||||
// install [plugin-name/url]
|
||||
if ((args == null) || (args.length == 0)) {
|
||||
return exitCmd(ExitStatus.USAGE, terminal, "plugin name is missing (type -h for help)");
|
||||
return exitCmd(ExitStatus.USAGE, terminal, "plugin name or url is missing (type -h for help)");
|
||||
}
|
||||
String name = args[0];
|
||||
|
||||
URL optionalPluginUrl = null;
|
||||
// try parsing cli argument as URL
|
||||
try {
|
||||
optionalPluginUrl = new URL(name);
|
||||
name = null;
|
||||
} catch (MalformedURLException e) {
|
||||
// we tried to parse the cli argument as url and failed
|
||||
// continue treating it as a symbolic plugin name like `analysis-icu` etc.
|
||||
}
|
||||
|
||||
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")) {
|
||||
|
@ -188,15 +200,15 @@ public class PluginManagerCliParser extends CliTool {
|
|||
outputMode = OutputMode.VERBOSE;
|
||||
}
|
||||
|
||||
return new Install(terminal, name, outputMode, url, timeout);
|
||||
return new Install(terminal, name, outputMode, optionalPluginUrl, timeout);
|
||||
}
|
||||
|
||||
final String name;
|
||||
private OutputMode outputMode;
|
||||
final String url;
|
||||
final URL url;
|
||||
final TimeValue timeout;
|
||||
|
||||
Install(Terminal terminal, String name, OutputMode outputMode, String url, TimeValue timeout) {
|
||||
Install(Terminal terminal, String name, OutputMode outputMode, URL url, TimeValue timeout) {
|
||||
super(terminal);
|
||||
this.name = name;
|
||||
this.outputMode = outputMode;
|
||||
|
@ -207,7 +219,11 @@ public class PluginManagerCliParser extends CliTool {
|
|||
@Override
|
||||
public ExitStatus execute(Settings settings, Environment env) throws Exception {
|
||||
PluginManager pluginManager = new PluginManager(env, url, outputMode, timeout);
|
||||
terminal.println("-> Installing " + Strings.nullToEmpty(name) + "...");
|
||||
if (name != null) {
|
||||
terminal.println("-> Installing " + Strings.nullToEmpty(name) + "...");
|
||||
} else {
|
||||
terminal.println("-> Installing from " + url + "...");
|
||||
}
|
||||
pluginManager.downloadAndExtract(name, terminal);
|
||||
return ExitStatus.OK;
|
||||
}
|
||||
|
|
|
@ -4,13 +4,13 @@ NAME
|
|||
|
||||
SYNOPSIS
|
||||
|
||||
plugin install <name>
|
||||
plugin install <name or url>
|
||||
|
||||
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 argument can be a <name> of one of the official plugins, or refer to a github repository
|
||||
|
||||
The notation of just specifying a plugin name, downloads an officially supported plugin.
|
||||
|
||||
|
@ -20,6 +20,8 @@ DESCRIPTION
|
|||
|
||||
The notation of 'username/repository' refers to a github repository.
|
||||
|
||||
The argument can be an valid <url> which points to a download or file location for the plugin to be loaded from.
|
||||
|
||||
EXAMPLES
|
||||
|
||||
plugin install analysis-kuromoji
|
||||
|
@ -28,6 +30,10 @@ EXAMPLES
|
|||
|
||||
plugin install lmenezes/elasticsearch-kopf
|
||||
|
||||
plugin install http://download.elasticsearch.org/elasticsearch/elasticsearch-analysis-kuromoji/elasticsearch-analysis-kuromoji-2.7.0.zip
|
||||
|
||||
plugin install file:/path/to/plugin/elasticsearch-analysis-kuromoji-2.7.0.zip
|
||||
|
||||
OFFICIAL PLUGINS
|
||||
|
||||
The following plugins are officially supported and can be installed by just referring to their name
|
||||
|
@ -49,8 +55,6 @@ OFFICIAL PLUGINS
|
|||
|
||||
OPTIONS
|
||||
|
||||
-u,--url URL to retrieve the plugin from
|
||||
|
||||
-t,--timeout Timeout until the plugin download is abort
|
||||
|
||||
-v,--verbose Verbose output
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.elasticsearch.plugins;
|
|||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.action.admin.cluster.node.info.PluginsInfo;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
|
@ -53,13 +54,14 @@ public class PluginInfoTests extends ESTestCase {
|
|||
Path pluginDir = createTempDir().resolve("fake-plugin");
|
||||
writeProperties(pluginDir,
|
||||
"description", "fake desc",
|
||||
"name", "my_plugin",
|
||||
"version", "1.0",
|
||||
"elasticsearch.version", Version.CURRENT.toString(),
|
||||
"java.version", System.getProperty("java.specification.version"),
|
||||
"jvm", "true",
|
||||
"classname", "FakePlugin");
|
||||
PluginInfo info = PluginInfo.readFromProperties(pluginDir);
|
||||
assertEquals("fake-plugin", info.getName());
|
||||
assertEquals("my_plugin", info.getName());
|
||||
assertEquals("fake desc", info.getDescription());
|
||||
assertEquals("1.0", info.getVersion());
|
||||
assertEquals("FakePlugin", info.getClassname());
|
||||
|
@ -69,9 +71,28 @@ public class PluginInfoTests extends ESTestCase {
|
|||
assertNull(info.getUrl());
|
||||
}
|
||||
|
||||
public void testReadFromPropertiesDescriptionMissing() throws Exception {
|
||||
public void testReadFromPropertiesNameMissing() throws Exception {
|
||||
Path pluginDir = createTempDir().resolve("fake-plugin");
|
||||
writeProperties(pluginDir);
|
||||
try {
|
||||
PluginInfo.readFromProperties(pluginDir);
|
||||
fail("expected missing name exception");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertTrue(e.getMessage().contains("Property [name] is missing in"));
|
||||
}
|
||||
|
||||
writeProperties(pluginDir, "name", "");
|
||||
try {
|
||||
PluginInfo.readFromProperties(pluginDir);
|
||||
fail("expected missing name exception");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertTrue(e.getMessage().contains("Property [name] is missing in"));
|
||||
}
|
||||
}
|
||||
|
||||
public void testReadFromPropertiesDescriptionMissing() throws Exception {
|
||||
Path pluginDir = createTempDir().resolve("fake-plugin");
|
||||
writeProperties(pluginDir, "name", "fake-plugin");
|
||||
try {
|
||||
PluginInfo.readFromProperties(pluginDir);
|
||||
fail("expected missing description exception");
|
||||
|
@ -82,7 +103,7 @@ public class PluginInfoTests extends ESTestCase {
|
|||
|
||||
public void testReadFromPropertiesVersionMissing() throws Exception {
|
||||
Path pluginDir = createTempDir().resolve("fake-plugin");
|
||||
writeProperties(pluginDir, "description", "fake desc");
|
||||
writeProperties(pluginDir, "description", "fake desc", "name", "fake-plugin");
|
||||
try {
|
||||
PluginInfo.readFromProperties(pluginDir);
|
||||
fail("expected missing version exception");
|
||||
|
@ -95,7 +116,8 @@ public class PluginInfoTests extends ESTestCase {
|
|||
Path pluginDir = createTempDir().resolve("fake-plugin");
|
||||
writeProperties(pluginDir,
|
||||
"description", "fake desc",
|
||||
"version", "1.0");
|
||||
"version", "1.0",
|
||||
"name", "my_plugin");
|
||||
try {
|
||||
PluginInfo.readFromProperties(pluginDir);
|
||||
fail("expected jvm or site exception");
|
||||
|
@ -108,6 +130,7 @@ public class PluginInfoTests extends ESTestCase {
|
|||
Path pluginDir = createTempDir().resolve("fake-plugin");
|
||||
writeProperties(pluginDir,
|
||||
"description", "fake desc",
|
||||
"name", "my_plugin",
|
||||
"version", "1.0",
|
||||
"jvm", "true");
|
||||
try {
|
||||
|
@ -122,6 +145,7 @@ public class PluginInfoTests extends ESTestCase {
|
|||
Path pluginDir = createTempDir().resolve("fake-plugin");
|
||||
writeProperties(pluginDir,
|
||||
"description", "fake desc",
|
||||
"name", "my_plugin",
|
||||
"elasticsearch.version", Version.CURRENT.toString(),
|
||||
"version", "1.0",
|
||||
"jvm", "true");
|
||||
|
@ -134,9 +158,11 @@ public class PluginInfoTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testReadFromPropertiesJavaVersionIncompatible() throws Exception {
|
||||
Path pluginDir = createTempDir().resolve("fake-plugin");
|
||||
String pluginName = "fake-plugin";
|
||||
Path pluginDir = createTempDir().resolve(pluginName);
|
||||
writeProperties(pluginDir,
|
||||
"description", "fake desc",
|
||||
"name", pluginName,
|
||||
"elasticsearch.version", Version.CURRENT.toString(),
|
||||
"java.version", "1000000.0",
|
||||
"classname", "FakePlugin",
|
||||
|
@ -146,7 +172,7 @@ public class PluginInfoTests extends ESTestCase {
|
|||
PluginInfo.readFromProperties(pluginDir);
|
||||
fail("expected incompatible java version exception");
|
||||
} catch (IllegalStateException e) {
|
||||
assertTrue(e.getMessage(), e.getMessage().contains("fake-plugin requires Java"));
|
||||
assertTrue(e.getMessage(), e.getMessage().contains(pluginName + " requires Java"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -156,6 +182,7 @@ public class PluginInfoTests extends ESTestCase {
|
|||
"description", "fake desc",
|
||||
"version", "1.0",
|
||||
"jvm", "true",
|
||||
"name", "my_plugin",
|
||||
"elasticsearch.version", "bogus");
|
||||
try {
|
||||
PluginInfo.readFromProperties(pluginDir);
|
||||
|
@ -169,6 +196,7 @@ public class PluginInfoTests extends ESTestCase {
|
|||
Path pluginDir = createTempDir().resolve("fake-plugin");
|
||||
writeProperties(pluginDir,
|
||||
"description", "fake desc",
|
||||
"name", "my_plugin",
|
||||
"version", "1.0",
|
||||
"jvm", "true",
|
||||
"elasticsearch.version", Version.V_1_7_0.toString());
|
||||
|
@ -184,6 +212,7 @@ public class PluginInfoTests extends ESTestCase {
|
|||
Path pluginDir = createTempDir().resolve("fake-plugin");
|
||||
writeProperties(pluginDir,
|
||||
"description", "fake desc",
|
||||
"name", "my_plugin",
|
||||
"version", "1.0",
|
||||
"elasticsearch.version", Version.CURRENT.toString(),
|
||||
"java.version", System.getProperty("java.specification.version"),
|
||||
|
@ -201,6 +230,7 @@ public class PluginInfoTests extends ESTestCase {
|
|||
Files.createDirectories(pluginDir.resolve("_site"));
|
||||
writeProperties(pluginDir,
|
||||
"description", "fake desc",
|
||||
"name", "my_plugin",
|
||||
"version", "1.0",
|
||||
"site", "true");
|
||||
PluginInfo info = PluginInfo.readFromProperties(pluginDir);
|
||||
|
@ -208,11 +238,12 @@ public class PluginInfoTests extends ESTestCase {
|
|||
assertFalse(info.isJvm());
|
||||
assertEquals("NA", info.getClassname());
|
||||
}
|
||||
|
||||
|
||||
public void testReadFromPropertiesSitePluginWithoutSite() throws Exception {
|
||||
Path pluginDir = createTempDir().resolve("fake-plugin");
|
||||
writeProperties(pluginDir,
|
||||
"description", "fake desc",
|
||||
"name", "my_plugin",
|
||||
"version", "1.0",
|
||||
"site", "true");
|
||||
try {
|
||||
|
|
|
@ -175,11 +175,13 @@ public class PluginManagerIT extends ESIntegTestCase {
|
|||
Path pluginDir = createTempDir().resolve("fake-plugin");
|
||||
String pluginUrl = createPlugin(pluginDir,
|
||||
"description", "fake desc",
|
||||
"name", "fake-plugin",
|
||||
"version", "1.0",
|
||||
"elasticsearch.version", Version.CURRENT.toString(),
|
||||
"java.version", System.getProperty("java.specification.version"),
|
||||
"jvm", "true",
|
||||
"classname", "FakePlugin");
|
||||
assertStatus("install --url " + pluginUrl, USAGE);
|
||||
assertStatus("install", USAGE);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -191,21 +193,22 @@ public class PluginManagerIT extends ESIntegTestCase {
|
|||
Files.createFile(pluginDir.resolve("bin").resolve("tool"));
|
||||
Files.createDirectories(pluginDir.resolve("config"));
|
||||
Files.createFile(pluginDir.resolve("config").resolve("file"));
|
||||
|
||||
|
||||
String pluginUrl = createPlugin(pluginDir,
|
||||
"description", "fake desc",
|
||||
"name", pluginName,
|
||||
"version", "1.0",
|
||||
"elasticsearch.version", Version.CURRENT.toString(),
|
||||
"java.version", System.getProperty("java.specification.version"),
|
||||
"jvm", "true",
|
||||
"classname", "FakePlugin");
|
||||
|
||||
|
||||
Environment env = initialSettings.v2();
|
||||
Path binDir = env.binFile();
|
||||
Path pluginBinDir = binDir.resolve(pluginName);
|
||||
|
||||
Path pluginConfigDir = env.configFile().resolve(pluginName);
|
||||
assertStatusOk("install " + pluginName + " --url " + pluginUrl + " --verbose");
|
||||
assertStatusOk("install " + pluginUrl + " --verbose");
|
||||
|
||||
terminal.getTerminalOutput().clear();
|
||||
assertStatusOk("list");
|
||||
|
@ -236,19 +239,20 @@ public class PluginManagerIT extends ESIntegTestCase {
|
|||
// create config/test.txt with contents 'version1'
|
||||
Files.createDirectories(pluginDir.resolve("config"));
|
||||
Files.write(pluginDir.resolve("config").resolve("test.txt"), "version1".getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
|
||||
String pluginUrl = createPlugin(pluginDir,
|
||||
"description", "fake desc",
|
||||
"name", pluginName,
|
||||
"version", "1.0",
|
||||
"elasticsearch.version", Version.CURRENT.toString(),
|
||||
"java.version", System.getProperty("java.specification.version"),
|
||||
"jvm", "true",
|
||||
"classname", "FakePlugin");
|
||||
|
||||
|
||||
Environment env = initialSettings.v2();
|
||||
Path pluginConfigDir = env.configFile().resolve(pluginName);
|
||||
|
||||
assertStatusOk(String.format(Locale.ROOT, "install %s --url %s --verbose", pluginName, pluginUrl));
|
||||
assertStatusOk(String.format(Locale.ROOT, "install %s --verbose", pluginUrl));
|
||||
|
||||
/*
|
||||
First time, our plugin contains:
|
||||
|
@ -275,13 +279,14 @@ public class PluginManagerIT extends ESIntegTestCase {
|
|||
Files.write(pluginDir.resolve("config").resolve("dir").resolve("subdir").resolve("testsubdir.txt"), "version1".getBytes(StandardCharsets.UTF_8));
|
||||
pluginUrl = createPlugin(pluginDir,
|
||||
"description", "fake desc",
|
||||
"name", pluginName,
|
||||
"version", "2.0",
|
||||
"elasticsearch.version", Version.CURRENT.toString(),
|
||||
"java.version", System.getProperty("java.specification.version"),
|
||||
"jvm", "true",
|
||||
"classname", "FakePlugin");
|
||||
|
||||
assertStatusOk(String.format(Locale.ROOT, "install %s --url %s --verbose", pluginName, pluginUrl));
|
||||
|
||||
assertStatusOk(String.format(Locale.ROOT, "install %s --verbose", pluginUrl));
|
||||
|
||||
assertFileContent(pluginConfigDir, "test.txt", "version1");
|
||||
assertFileContent(pluginConfigDir, "test.txt.new", "version2");
|
||||
|
@ -311,13 +316,14 @@ public class PluginManagerIT extends ESIntegTestCase {
|
|||
Files.write(pluginDir.resolve("config").resolve("dir").resolve("subdir").resolve("testsubdir.txt"), "version2".getBytes(StandardCharsets.UTF_8));
|
||||
pluginUrl = createPlugin(pluginDir,
|
||||
"description", "fake desc",
|
||||
"name", pluginName,
|
||||
"version", "3.0",
|
||||
"elasticsearch.version", Version.CURRENT.toString(),
|
||||
"java.version", System.getProperty("java.specification.version"),
|
||||
"jvm", "true",
|
||||
"classname", "FakePlugin");
|
||||
|
||||
assertStatusOk(String.format(Locale.ROOT, "install %s --url %s --verbose", pluginName, pluginUrl));
|
||||
assertStatusOk(String.format(Locale.ROOT, "install %s --verbose", pluginUrl));
|
||||
|
||||
assertFileContent(pluginConfigDir, "test.txt", "version1");
|
||||
assertFileContent(pluginConfigDir, "test2.txt", "version1");
|
||||
|
@ -339,17 +345,18 @@ public class PluginManagerIT extends ESIntegTestCase {
|
|||
Files.createFile(pluginDir.resolve("bin").resolve("tool"));;
|
||||
String pluginUrl = createPlugin(pluginDir,
|
||||
"description", "fake desc",
|
||||
"name", "fake-plugin",
|
||||
"version", "1.0",
|
||||
"elasticsearch.version", Version.CURRENT.toString(),
|
||||
"java.version", System.getProperty("java.specification.version"),
|
||||
"jvm", "true",
|
||||
"classname", "FakePlugin");
|
||||
|
||||
|
||||
Environment env = initialSettings.v2();
|
||||
Path binDir = env.binFile();
|
||||
Path pluginBinDir = binDir.resolve(pluginName);
|
||||
|
||||
assertStatusOk(String.format(Locale.ROOT, "install %s --url %s --verbose", pluginName, pluginUrl));
|
||||
assertStatusOk(String.format(Locale.ROOT, "install %s --verbose", pluginUrl));
|
||||
assertThatPluginIsListed(pluginName);
|
||||
assertDirectoryExists(pluginBinDir);
|
||||
}
|
||||
|
@ -373,12 +380,13 @@ public class PluginManagerIT extends ESIntegTestCase {
|
|||
Path pluginDir = createTempDir().resolve(pluginName);
|
||||
String pluginUrl = createPlugin(pluginDir,
|
||||
"description", "fake desc",
|
||||
"name", pluginName,
|
||||
"version", "1.0",
|
||||
"elasticsearch.version", Version.CURRENT.toString(),
|
||||
"java.version", System.getProperty("java.specification.version"),
|
||||
"jvm", "true",
|
||||
"classname", "FakePlugin");
|
||||
assertStatusOk(String.format(Locale.ROOT, "install %s --url %s --verbose", pluginName, pluginUrl));
|
||||
assertStatusOk(String.format(Locale.ROOT, "install %s --verbose", pluginUrl));
|
||||
assertThatPluginIsListed(pluginName);
|
||||
}
|
||||
|
||||
|
@ -389,10 +397,11 @@ public class PluginManagerIT extends ESIntegTestCase {
|
|||
Files.createDirectories(pluginDir.resolve("_site"));
|
||||
Files.createFile(pluginDir.resolve("_site").resolve("somefile"));
|
||||
String pluginUrl = createPlugin(pluginDir,
|
||||
"description", "fake desc",
|
||||
"version", "1.0",
|
||||
"site", "true");
|
||||
assertStatusOk(String.format(Locale.ROOT, "install %s --url %s --verbose", pluginName, pluginUrl));
|
||||
"description", "fake desc",
|
||||
"name", pluginName,
|
||||
"version", "1.0",
|
||||
"site", "true");
|
||||
assertStatusOk(String.format(Locale.ROOT, "install %s --verbose", pluginUrl));
|
||||
assertThatPluginIsListed(pluginName);
|
||||
// We want to check that Plugin Manager moves content to _site
|
||||
assertFileExists(initialSettings.v2().pluginsFile().resolve(pluginName).resolve("_site"));
|
||||
|
@ -408,7 +417,7 @@ public class PluginManagerIT extends ESIntegTestCase {
|
|||
"description", "fake desc",
|
||||
"version", "1.0",
|
||||
"site", "true");
|
||||
assertStatus(String.format(Locale.ROOT, "install %s --url %s --verbose", pluginName, pluginUrl),
|
||||
assertStatus(String.format(Locale.ROOT, "install %s --verbose", pluginUrl),
|
||||
ExitStatus.IO_ERROR);
|
||||
assertThatPluginIsNotListed(pluginName);
|
||||
assertFileNotExists(initialSettings.v2().pluginsFile().resolve(pluginName).resolve("_site"));
|
||||
|
@ -419,7 +428,7 @@ public class PluginManagerIT extends ESIntegTestCase {
|
|||
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));
|
||||
assertStatusOk(String.format(Locale.ROOT, "install %s --verbose", pluginCoordinates));
|
||||
}
|
||||
assertThatPluginIsListed(pluginName);
|
||||
|
||||
|
@ -493,15 +502,16 @@ public class PluginManagerIT extends ESIntegTestCase {
|
|||
@Test
|
||||
public void testRemovePlugin() throws Exception {
|
||||
String pluginName = "plugintest";
|
||||
Path pluginDir = createTempDir().resolve(pluginName);
|
||||
Path pluginDir = createTempDir().resolve(pluginName);
|
||||
String pluginUrl = createPlugin(pluginDir,
|
||||
"description", "fake desc",
|
||||
"name", pluginName,
|
||||
"version", "1.0.0",
|
||||
"elasticsearch.version", Version.CURRENT.toString(),
|
||||
"java.version", System.getProperty("java.specification.version"),
|
||||
"jvm", "true",
|
||||
"classname", "FakePlugin");
|
||||
|
||||
|
||||
// We want to remove plugin with plugin short name
|
||||
singlePluginInstallAndRemove("plugintest", "plugintest", pluginUrl);
|
||||
|
||||
|
@ -561,7 +571,7 @@ public class PluginManagerIT extends ESIntegTestCase {
|
|||
|
||||
@Test
|
||||
public void testThatBasicAuthIsRejectedOnHttp() throws Exception {
|
||||
assertStatus(String.format(Locale.ROOT, "install foo --url http://user:pass@localhost:12345/foo.zip --verbose"), CliTool.ExitStatus.IO_ERROR);
|
||||
assertStatus(String.format(Locale.ROOT, "install http://user:pass@localhost:12345/foo.zip --verbose"), CliTool.ExitStatus.IO_ERROR);
|
||||
assertThat(terminal.getTerminalOutput(), hasItem(containsString("Basic auth is only supported for HTTPS!")));
|
||||
}
|
||||
|
||||
|
@ -598,7 +608,7 @@ public class PluginManagerIT extends ESIntegTestCase {
|
|||
Channel channel = serverBootstrap.bind(new InetSocketAddress("localhost", 0));
|
||||
int port = ((InetSocketAddress) channel.getLocalAddress()).getPort();
|
||||
// IO_ERROR because there is no real file delivered...
|
||||
assertStatus(String.format(Locale.ROOT, "install foo --url https://user:pass@localhost:%s/foo.zip --verbose --timeout 1s", port), ExitStatus.IO_ERROR);
|
||||
assertStatus(String.format(Locale.ROOT, "install https://user:pass@localhost:%s/foo.zip --verbose --timeout 1s", port), ExitStatus.IO_ERROR);
|
||||
|
||||
// ensure that we did not try any other data source like download.elastic.co, in case we specified our own local URL
|
||||
assertThat(terminal.getTerminalOutput(), not(hasItem(containsString("download.elastic.co"))));
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
site=true
|
||||
description=anotherplugin
|
||||
version=1.0
|
||||
name=anotherplugin
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
site=true
|
||||
description=dummy
|
||||
version=1.0
|
||||
name=dummy
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
site=true
|
||||
description=subdir
|
||||
version=1.0
|
||||
name=subdir
|
||||
|
|
|
@ -87,8 +87,6 @@
|
|||
<run-script script="@{home}/bin/plugin">
|
||||
<nested>
|
||||
<arg value="install"/>
|
||||
<arg value="@{name}"/>
|
||||
<arg value="-u"/>
|
||||
<arg value="${url}"/>
|
||||
</nested>
|
||||
</run-script>
|
||||
|
|
|
@ -36,6 +36,9 @@ description=${project.description}
|
|||
# 'version': plugin's version
|
||||
version=${project.version}
|
||||
#
|
||||
# 'name': the plugin name
|
||||
name=${elasticsearch.plugin.name}
|
||||
|
||||
### mandatory elements for site plugins:
|
||||
#
|
||||
# 'site': set to true to indicate contents of the _site/
|
||||
|
|
|
@ -84,15 +84,15 @@ A plugin can also be downloaded directly from a custom location by specifying th
|
|||
|
||||
[source,shell]
|
||||
-----------------------------------
|
||||
sudo bin/plugin install [plugin-name] --url [url] <1>
|
||||
sudo bin/plugin install [url] <1>
|
||||
-----------------------------------
|
||||
<1> Both the URL and the plugin name must be specified.
|
||||
<1> must be a valid URL, the plugin name is determined from its descriptor.
|
||||
|
||||
For instance, to install a plugin from your local file system, you could run:
|
||||
|
||||
[source,shell]
|
||||
-----------------------------------
|
||||
sudo bin/plugin install my_plugin --url file:/path/to/plugin.zip
|
||||
sudo bin/plugin install file:/path/to/plugin.zip
|
||||
-----------------------------------
|
||||
|
||||
[[listing-removing]]
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
<properties>
|
||||
<elasticsearch.assembly.descriptor>${elasticsearch.tools.directory}/plugin-metadata/plugin-assembly.xml</elasticsearch.assembly.descriptor>
|
||||
<elasticsearch.assembly.appendId>false</elasticsearch.assembly.appendId>
|
||||
<elasticsearch.plugin.name>${project.artifactId}</elasticsearch.plugin.name>
|
||||
<elasticsearch.plugin.jvm>true</elasticsearch.plugin.jvm>
|
||||
<elasticsearch.plugin.isolated>true</elasticsearch.plugin.isolated>
|
||||
<elasticsearch.plugin.site>false</elasticsearch.plugin.site>
|
||||
|
@ -365,6 +366,7 @@
|
|||
<rules>
|
||||
<requireProperty>
|
||||
<property>elasticsearch.plugin.classname</property>
|
||||
<property>elasticsearch.plugin.name</property>
|
||||
</requireProperty>
|
||||
</rules>
|
||||
</configuration>
|
||||
|
|
Loading…
Reference in New Issue