From 8454d4955292c10fa875a97a8ccfb8d4e6c6d53f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BCscher?= Date: Fri, 7 Aug 2015 16:05:39 +0200 Subject: [PATCH] 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 --- .../org/elasticsearch/plugins/PluginInfo.java | 15 +++-- .../elasticsearch/plugins/PluginManager.java | 37 +++++++----- .../plugins/PluginManagerCliParser.java | 34 ++++++++--- .../elasticsearch/plugins/plugin-install.help | 12 ++-- .../plugins/PluginInfoTests.java | 45 ++++++++++++--- .../plugins/PluginManagerIT.java | 56 +++++++++++-------- .../plugin-descriptor.properties | 1 + .../dummy/plugin-descriptor.properties | 1 + .../subdir/plugin-descriptor.properties | 1 + .../main/resources/ant/integration-tests.xml | 2 - .../plugin-descriptor.properties | 3 + docs/plugins/plugin-script.asciidoc | 6 +- plugins/pom.xml | 2 + 13 files changed, 148 insertions(+), 67 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/plugins/PluginInfo.java b/core/src/main/java/org/elasticsearch/plugins/PluginInfo.java index 66f24e3a8c8..20b5fe28fff 100644 --- a/core/src/main/java/org/elasticsearch/plugins/PluginInfo.java +++ b/core/src/main/java/org/elasticsearch/plugins/PluginInfo.java @@ -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 */ diff --git a/core/src/main/java/org/elasticsearch/plugins/PluginManager.java b/core/src/main/java/org/elasticsearch/plugins/PluginManager.java index 234d719f734..3a3e11e0b89 100644 --- a/core/src/main/java/org/elasticsearch/plugins/PluginManager.java +++ b/core/src/main/java/org/elasticsearch/plugins/PluginManager.java @@ -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); } diff --git a/core/src/main/java/org/elasticsearch/plugins/PluginManagerCliParser.java b/core/src/main/java/org/elasticsearch/plugins/PluginManagerCliParser.java index 3732e8bda08..7f521fd4339 100644 --- a/core/src/main/java/org/elasticsearch/plugins/PluginManagerCliParser.java +++ b/core/src/main/java/org/elasticsearch/plugins/PluginManagerCliParser.java @@ -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; } diff --git a/core/src/main/resources/org/elasticsearch/plugins/plugin-install.help b/core/src/main/resources/org/elasticsearch/plugins/plugin-install.help index 9aa943da46c..e09c1bdfaf7 100644 --- a/core/src/main/resources/org/elasticsearch/plugins/plugin-install.help +++ b/core/src/main/resources/org/elasticsearch/plugins/plugin-install.help @@ -4,13 +4,13 @@ NAME SYNOPSIS - plugin install + plugin install DESCRIPTION This command installs an elasticsearch plugin - 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 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 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 diff --git a/core/src/test/java/org/elasticsearch/plugins/PluginInfoTests.java b/core/src/test/java/org/elasticsearch/plugins/PluginInfoTests.java index 2cdf82322bb..64b2ae59312 100644 --- a/core/src/test/java/org/elasticsearch/plugins/PluginInfoTests.java +++ b/core/src/test/java/org/elasticsearch/plugins/PluginInfoTests.java @@ -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 { diff --git a/core/src/test/java/org/elasticsearch/plugins/PluginManagerIT.java b/core/src/test/java/org/elasticsearch/plugins/PluginManagerIT.java index 4acb818c180..e4d13b677b2 100644 --- a/core/src/test/java/org/elasticsearch/plugins/PluginManagerIT.java +++ b/core/src/test/java/org/elasticsearch/plugins/PluginManagerIT.java @@ -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")))); diff --git a/core/src/test/resources/org/elasticsearch/test_plugins/anotherplugin/plugin-descriptor.properties b/core/src/test/resources/org/elasticsearch/test_plugins/anotherplugin/plugin-descriptor.properties index 8a08b726b50..66741adf220 100644 --- a/core/src/test/resources/org/elasticsearch/test_plugins/anotherplugin/plugin-descriptor.properties +++ b/core/src/test/resources/org/elasticsearch/test_plugins/anotherplugin/plugin-descriptor.properties @@ -1,3 +1,4 @@ site=true description=anotherplugin version=1.0 +name=anotherplugin diff --git a/core/src/test/resources/org/elasticsearch/test_plugins/dummy/plugin-descriptor.properties b/core/src/test/resources/org/elasticsearch/test_plugins/dummy/plugin-descriptor.properties index 71f5a590274..91ae24c8201 100644 --- a/core/src/test/resources/org/elasticsearch/test_plugins/dummy/plugin-descriptor.properties +++ b/core/src/test/resources/org/elasticsearch/test_plugins/dummy/plugin-descriptor.properties @@ -1,3 +1,4 @@ site=true description=dummy version=1.0 +name=dummy diff --git a/core/src/test/resources/org/elasticsearch/test_plugins/subdir/plugin-descriptor.properties b/core/src/test/resources/org/elasticsearch/test_plugins/subdir/plugin-descriptor.properties index f6a05a4f499..fa8950e2a55 100644 --- a/core/src/test/resources/org/elasticsearch/test_plugins/subdir/plugin-descriptor.properties +++ b/core/src/test/resources/org/elasticsearch/test_plugins/subdir/plugin-descriptor.properties @@ -1,3 +1,4 @@ site=true description=subdir version=1.0 +name=subdir diff --git a/dev-tools/src/main/resources/ant/integration-tests.xml b/dev-tools/src/main/resources/ant/integration-tests.xml index f5e87c033e3..307eaba01ee 100644 --- a/dev-tools/src/main/resources/ant/integration-tests.xml +++ b/dev-tools/src/main/resources/ant/integration-tests.xml @@ -87,8 +87,6 @@ - - diff --git a/dev-tools/src/main/resources/plugin-metadata/plugin-descriptor.properties b/dev-tools/src/main/resources/plugin-metadata/plugin-descriptor.properties index 26bee6df895..09b68b7a24d 100644 --- a/dev-tools/src/main/resources/plugin-metadata/plugin-descriptor.properties +++ b/dev-tools/src/main/resources/plugin-metadata/plugin-descriptor.properties @@ -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/ diff --git a/docs/plugins/plugin-script.asciidoc b/docs/plugins/plugin-script.asciidoc index 06263d730ad..fc1c91c1530 100644 --- a/docs/plugins/plugin-script.asciidoc +++ b/docs/plugins/plugin-script.asciidoc @@ -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]] diff --git a/plugins/pom.xml b/plugins/pom.xml index 5bc7f5f83f2..90bba7e1776 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -22,6 +22,7 @@ ${elasticsearch.tools.directory}/plugin-metadata/plugin-assembly.xml false + ${project.artifactId} true true false @@ -365,6 +366,7 @@ elasticsearch.plugin.classname + elasticsearch.plugin.name