Plugin Manager should support -remove group/artifact/version naming

When installing a plugin, we use:

```sh
bin/plugin --install groupid/artifactid/version
```

But when removing the plugin, we only support:

```sh
bin/plugin --remove dirname
```

where `dirname` is the directory name of the plugin under `/plugins` dir.

Closes #3421.
This commit is contained in:
David Pilato 2013-09-04 19:38:05 +02:00
parent f3c0e39380
commit 764aa54f2d
3 changed files with 178 additions and 105 deletions

View File

@ -89,6 +89,19 @@ will not start.
A list of the currently loaded plugins can be retrieved using the
<<cluster-nodes-info,Node Info API>>.
[float]
==== Removing plugins
Removing plugins can either be done manually by removing them under the
`plugins` directory, or using the `plugin` script.
Removing plugins typically take the following form:
[source,shell]
-----------------------------------
plugin --remove <pluginname>
-----------------------------------
[float]
=== Known Plugins

View File

@ -35,10 +35,9 @@ import javax.net.ssl.X509TrustManager;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@ -97,7 +96,13 @@ public class PluginManager {
throw new IOException("plugin directory " + environment.pluginsFile() + " is read only");
}
File pluginFile = new File(environment.pluginsFile(), name + ".zip");
PluginHandle pluginHandle = PluginHandle.parse(name);
File pluginFile = pluginHandle.distroFile(environment);
// extract the plugin
File extractLocation = pluginHandle.extractedDir(environment);
if (extractLocation.exists()) {
throw new IOException("plugin directory " + extractLocation.getAbsolutePath() + " already exists. To update the plugin, uninstall it first using -remove " + name + " command");
}
// first, try directly from the URL provided
boolean downloaded = false;
@ -116,92 +121,17 @@ public class PluginManager {
}
}
// now, try as a path name...
if (!downloaded) {
if (name.indexOf('/') != -1) {
// github repo
String[] elements = name.split("/");
String userName = elements[0];
String repoName = elements[1];
String version = null;
if (elements.length > 2) {
version = elements[2];
}
// the installation file should not include the userName, just the repoName
name = repoName;
if (name.startsWith("elasticsearch-")) {
// remove elasticsearch- prefix
name = name.substring("elasticsearch-".length());
} else if (name.startsWith("es-")) {
// remove es- prefix
name = name.substring("es-".length());
}
// update the plugin file name to reflect the extracted name
pluginFile = new File(environment.pluginsFile(), name + ".zip");
if (version != null) {
URL pluginUrl = new URL("http://download.elasticsearch.org/" + userName + "/" + repoName + "/" + repoName + "-" + version + ".zip");
System.out.println("Trying " + pluginUrl.toExternalForm() + "...");
try {
downloadHelper.download(pluginUrl, pluginFile, new HttpDownloadHelper.VerboseProgress(System.out));
downloaded = true;
} catch (Exception e) {
if (verbose) {
System.out.println("Failed: " + ExceptionsHelper.detailedMessage(e));
}
}
if (!downloaded) {
// try maven, see if its there... (both central and sonatype)
pluginUrl = new URL("http://search.maven.org/remotecontent?filepath=" + userName.replace('.', '/') + "/" + repoName + "/" + version + "/" + repoName + "-" + version + ".zip");
System.out.println("Trying " + pluginUrl.toExternalForm() + "...");
try {
downloadHelper.download(pluginUrl, pluginFile, new HttpDownloadHelper.VerboseProgress(System.out));
downloaded = true;
} catch (Exception e) {
if (verbose) {
System.out.println("Failed: " + ExceptionsHelper.detailedMessage(e));
}
}
if (!downloaded) {
pluginUrl = new URL("https://oss.sonatype.org/service/local/repositories/releases/content/" + userName.replace('.', '/') + "/" + repoName + "/" + version + "/" + repoName + "-" + version + ".zip");
System.out.println("Trying " + pluginUrl.toExternalForm() + "...");
try {
downloadHelper.download(pluginUrl, pluginFile, new HttpDownloadHelper.VerboseProgress(System.out));
downloaded = true;
} catch (Exception e) {
if (verbose) {
System.out.println("Failed: " + ExceptionsHelper.detailedMessage(e));
}
}
}
}
if (!downloaded) {
// try it as a site plugin tagged
pluginUrl = new URL("https://github.com/" + userName + "/" + repoName + "/archive/v" + version + ".zip");
System.out.println("Trying " + pluginUrl.toExternalForm() + "... (assuming site plugin)");
try {
downloadHelper.download(pluginUrl, pluginFile, new HttpDownloadHelper.VerboseProgress(System.out));
downloaded = true;
} catch (Exception e1) {
// ignore
if (verbose) {
System.out.println("Failed: " + ExceptionsHelper.detailedMessage(e1));
}
}
}
} else {
// assume site plugin, download master....
URL pluginUrl = new URL("https://github.com/" + userName + "/" + repoName + "/archive/master.zip");
System.out.println("Trying " + pluginUrl.toExternalForm() + "... (assuming site plugin)");
try {
downloadHelper.download(pluginUrl, pluginFile, new HttpDownloadHelper.VerboseProgress(System.out));
downloaded = true;
} catch (Exception e2) {
// ignore
if (verbose) {
System.out.println("Failed: " + ExceptionsHelper.detailedMessage(e2));
}
// We try all possible locations
for (URL url: pluginHandle.urls()) {
System.out.println("Trying " + url.toExternalForm() + "...");
try {
downloadHelper.download(url, pluginFile, new HttpDownloadHelper.VerboseProgress(System.out));
downloaded = true;
break;
} catch (Exception e) {
if (verbose) {
System.out.println("Failed: " + ExceptionsHelper.detailedMessage(e));
}
}
}
@ -211,11 +141,6 @@ public class PluginManager {
throw new IOException("failed to download out of all possible locations..., use -verbose to get detailed information");
}
// extract the plugin
File extractLocation = new File(environment.pluginsFile(), name);
if (extractLocation.exists()) {
throw new IOException("plugin directory " + extractLocation.getAbsolutePath() + " already exists. To update the plugin, uninstall it first using -remove " + name + " command");
}
ZipFile zipFile = null;
try {
zipFile = new ZipFile(pluginFile);
@ -259,7 +184,7 @@ public class PluginManager {
File binFile = new File(extractLocation, "bin");
if (binFile.exists() && binFile.isDirectory()) {
File toLocation = new File(new File(environment.homeFile(), "bin"), name);
File toLocation = pluginHandle.binDir(environment);
System.out.println("Found bin, moving to " + toLocation.getAbsolutePath());
FileSystemUtils.deleteRecursively(toLocation);
binFile.renameTo(toLocation);
@ -282,22 +207,38 @@ public class PluginManager {
}
public void removePlugin(String name) throws IOException {
File pluginToDelete = new File(environment.pluginsFile(), name);
PluginHandle pluginHandle = PluginHandle.parse(name);
boolean removed = false;
File pluginToDelete = pluginHandle.extractedDir(environment);
if (pluginToDelete.exists()) {
FileSystemUtils.deleteRecursively(pluginToDelete, true);
removed = true;
}
pluginToDelete = new File(environment.pluginsFile(), name + ".zip");
pluginToDelete = pluginHandle.distroFile(environment);
if (pluginToDelete.exists()) {
pluginToDelete.delete();
removed = true;
}
File binLocation = new File(new File(environment.homeFile(), "bin"), name);
File binLocation = pluginHandle.binDir(environment);
if (binLocation.exists()) {
FileSystemUtils.deleteRecursively(binLocation);
removed = true;
}
if (removed) {
System.out.println("Removed " + name);
} else {
System.out.println("Plugin " + name + " not found. Run plugin --list to get list of installed plugins.");
}
}
public File[] getListInstalledPlugins() {
File[] plugins = environment.pluginsFile().listFiles();
return plugins;
}
public void listInstalledPlugins() {
File[] plugins = environment.pluginsFile().listFiles();
File[] plugins = getListInstalledPlugins();
System.out.println("Installed plugins:");
if (plugins == null || plugins.length == 0) {
System.out.println(" - No plugin detected in " + environment.pluginsFile().getAbsolutePath());
@ -461,4 +402,95 @@ public class PluginManager {
System.out.println(" " + message);
}
}
/**
* Helper class to extract properly user name, repository name, version and plugin name
* from plugin name given by a user.
*/
static class PluginHandle {
final String name;
final String version;
final String user;
final String repo;
PluginHandle(String name, String version, String user, String repo) {
this.name = name;
this.version = version;
this.user = user;
this.repo = repo;
}
List<URL> urls() {
List<URL> urls = new ArrayList<URL>();
if (version != null) {
// Elasticsearch download service
addUrl(urls, "http://download.elasticsearch.org/" + user + "/" + repo + "/" + repo + "-" + version + ".zip");
// Maven central repository
addUrl(urls, "http://search.maven.org/remotecontent?filepath=" + user.replace('.', '/') + "/" + repo + "/" + version + "/" + repo + "-" + version + ".zip");
// Sonatype repository
addUrl(urls, "https://oss.sonatype.org/service/local/repositories/releases/content/" + user.replace('.', '/') + "/" + repo + "/" + version + "/" + repo + "-" + version + ".zip");
// Github repository
addUrl(urls, "https://github.com/" + user + "/" + repo + "/archive/v" + version + ".zip");
}
// Github repository for master branch (assume site)
addUrl(urls, "https://github.com/" + user + "/" + repo + "/archive/master.zip");
return urls;
}
private static void addUrl(List<URL> urls, String url) {
try {
URL _url = new URL(url);
urls.add(new URL(url));
} catch (MalformedURLException e) {
// We simply ignore malformed URL
}
}
File distroFile(Environment env) {
return new File(env.pluginsFile(), name + ".zip");
}
File extractedDir(Environment env) {
return new File(env.pluginsFile(), name);
}
File binDir(Environment env) {
return new File(new File(env.homeFile(), "bin"), name);
}
static PluginHandle parse(String name) {
String[] elements = name.split("/");
// We first consider the simplest form: pluginname
String repo = elements[0];
String user = null;
String version = null;
// We consider the form: username/pluginname
if (elements.length > 1) {
user = elements[0];
repo = elements[1];
// We consider the form: username/pluginname/version
if (elements.length > 2) {
version = elements[2];
}
}
if (repo.startsWith("elasticsearch-")) {
// remove elasticsearch- prefix
String endname = repo.substring("elasticsearch-".length());
return new PluginHandle(endname, version, user, repo);
}
if (name.startsWith("es-")) {
// remove es- prefix
String endname = repo.substring("es-".length());
return new PluginHandle(endname, version, user, repo);
}
return new PluginHandle(repo, version, user, repo);
}
}
}

View File

@ -38,11 +38,10 @@ import org.junit.Before;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.Matchers.*;
public class PluginManagerTests extends AbstractNodesTests {
@ -102,14 +101,17 @@ public class PluginManagerTests extends AbstractNodesTests {
assertPluginAvailable(node, pluginName);
}
private static void downloadAndExtract(String pluginName, String pluginUrl) throws Exception {
private static PluginManager pluginManager(String pluginUrl) {
Tuple<Settings, Environment> initialSettings = InternalSettingsPerparer.prepareSettings(
ImmutableSettings.settingsBuilder().build(), false);
if (!initialSettings.v2().pluginsFile().exists()) {
FileSystemUtils.mkdirs(initialSettings.v2().pluginsFile());
}
PluginManager pluginManager = new PluginManager(initialSettings.v2(), pluginUrl);
pluginManager.downloadAndExtract(pluginName, false);
return new PluginManager(initialSettings.v2(), pluginUrl);
}
private static void downloadAndExtract(String pluginName, String pluginUrl) throws IOException {
pluginManager(pluginUrl).downloadAndExtract(pluginName, false);
}
private Node startNode() {
@ -152,4 +154,30 @@ public class PluginManagerTests extends AbstractNodesTests {
private void deletePluginsFolder() {
FileSystemUtils.deleteRecursively(new File(PLUGIN_DIR));
}
private void singlePluginInstallAndRemove(String pluginName, String pluginCoordinates) throws IOException {
PluginManager pluginManager = pluginManager(pluginCoordinates);
pluginManager.downloadAndExtract("plugin", false);
File[] plugins = pluginManager.getListInstalledPlugins();
assertThat(plugins, notNullValue());
assertThat(plugins.length, is(1));
// We remove it
pluginManager.removePlugin(pluginName);
plugins = pluginManager.getListInstalledPlugins();
assertThat(plugins, notNullValue());
assertThat(plugins.length, is(0));
}
@Test
public void testRemovePlugin() throws Exception {
// We want to remove plugin with plugin short name
singlePluginInstallAndRemove("plugin", "file://".concat(PluginManagerTests.class.getResource("plugin_without_folders.zip").getFile()));
// We want to remove plugin with groupid/artifactid/version form
singlePluginInstallAndRemove("groupid/plugin/1.0.0", "file://".concat(PluginManagerTests.class.getResource("plugin_without_folders.zip").getFile()));
// We want to remove plugin with groupid/artifactid form
singlePluginInstallAndRemove("groupid/plugin", "file://".concat(PluginManagerTests.class.getResource("plugin_without_folders.zip").getFile()));
}
}