summaryrefslogtreecommitdiff
path: root/core/src/test/java/org/elasticsearch/plugins
diff options
context:
space:
mode:
authorJason Tedor <jason@tedor.me>2017-04-21 15:50:44 -0400
committerGitHub <noreply@github.com>2017-04-21 15:50:44 -0400
commitfe91c721519ffe706ee44e375adcad8d5a303e66 (patch)
treed8d6790b14b9d880e61d83382af3de099e86f9fc /core/src/test/java/org/elasticsearch/plugins
parent2ca7072b2447d374eb9c58cf81477c2aa01c351c (diff)
Use a marker file when removing a plugin
Today when removing a plugin, we attempt to move the plugin directory to a temporary directory and then delete that directory from the filesystem. We do this to avoid a plugin being in a half-removed state. We previously tried an atomic move, and fell back to a non-atomic move if that failed. Atomic moves can fail on union filesystems when the plugin directory is not in the top layer of the filesystem. Interestingly, the regular move can fail as well. This is because when the JDK is executing such a move, it first tries to rename the source directory to the target directory and if this fails with EXDEV (as in the case of an atomic move failing), it falls back to copying the source to the target, and then attempts to rmdir the source. The bug here is that the JDK never deleted the contents of the source so the rmdir will always fail (except in the case of an empty directory). Given all this silliness, we were inspired to find a different strategy. The strategy is simple. We will add a marker file to the plugin directory that indicates the plugin is in a state of removal. This file will be the last file out the door during removal. If this file exists during startup, we fail startup. Relates #24252
Diffstat (limited to 'core/src/test/java/org/elasticsearch/plugins')
-rw-r--r--core/src/test/java/org/elasticsearch/plugins/PluginsServiceTests.java30
1 files changed, 30 insertions, 0 deletions
diff --git a/core/src/test/java/org/elasticsearch/plugins/PluginsServiceTests.java b/core/src/test/java/org/elasticsearch/plugins/PluginsServiceTests.java
index f4aae5232c..89c65ad2c8 100644
--- a/core/src/test/java/org/elasticsearch/plugins/PluginsServiceTests.java
+++ b/core/src/test/java/org/elasticsearch/plugins/PluginsServiceTests.java
@@ -20,6 +20,7 @@
package org.elasticsearch.plugins;
import org.apache.lucene.util.LuceneTestCase;
+import org.elasticsearch.Version;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.index.IndexModule;
@@ -30,6 +31,7 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
+import java.util.Locale;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.hasToString;
@@ -121,4 +123,32 @@ public class PluginsServiceTests extends ESTestCase {
assertThat(e, hasToString(containsString(expected)));
}
+ public void testStartupWithRemovingMarker() throws IOException {
+ final Path home = createTempDir();
+ final Settings settings =
+ Settings.builder()
+ .put(Environment.PATH_HOME_SETTING.getKey(), home)
+ .build();
+ final Path fake = home.resolve("plugins").resolve("fake");
+ Files.createDirectories(fake);
+ Files.createFile(fake.resolve("plugin.jar"));
+ final Path removing = fake.resolve(".removing-fake");
+ Files.createFile(fake.resolve(".removing-fake"));
+ PluginTestUtil.writeProperties(
+ fake,
+ "description", "fake",
+ "name", "fake",
+ "version", "1.0.0",
+ "elasticsearch.version", Version.CURRENT.toString(),
+ "java.version", System.getProperty("java.specification.version"),
+ "classname", "Fake",
+ "has.native.controller", "false");
+ final IllegalStateException e = expectThrows(IllegalStateException.class, () -> newPluginsService(settings));
+ final String expected = String.format(
+ Locale.ROOT,
+ "found file [%s] from a failed attempt to remove the plugin [fake]; execute [elasticsearch-plugin remove fake]",
+ removing);
+ assertThat(e, hasToString(containsString(expected)));
+ }
+
}