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:
parent
f3c0e39380
commit
764aa54f2d
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue