Add tests of POSIX handling for installing plugins

This commit refactors the unit tests for installing plugins to test
against mock filesystems (as well as the native filesystem) for better
test coverage. This commit also adds tests that cover the POSIX
attributes handling when installing plugins (e.g., ensuring that the
plugins directory has the right permissions, the bin directory has
execute permissions, and the config directory has the same owner and
group as its parent).
This commit is contained in:
Jason Tedor 2016-03-20 17:47:39 -04:00
parent 554eb8aa87
commit 6db6c15d06
6 changed files with 213 additions and 87 deletions

View File

@ -27,7 +27,7 @@ import java.nio.file.FileSystems;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
/** /**
* Utilities for creating a Path from names, * Utilities for creating a Path from names,
* or accessing the default FileSystem. * or accessing the default FileSystem.
* <p> * <p>
@ -39,14 +39,14 @@ import java.nio.file.Paths;
public final class PathUtils { public final class PathUtils {
/** no instantiation */ /** no instantiation */
private PathUtils() {} private PathUtils() {}
/** the actual JDK default */ /** the actual JDK default */
static final FileSystem ACTUAL_DEFAULT = FileSystems.getDefault(); static final FileSystem ACTUAL_DEFAULT = FileSystems.getDefault();
/** can be changed by tests */ /** can be changed by tests */
static volatile FileSystem DEFAULT = ACTUAL_DEFAULT; static volatile FileSystem DEFAULT = ACTUAL_DEFAULT;
/** /**
* Returns a {@code Path} from name components. * Returns a {@code Path} from name components.
* <p> * <p>
* This works just like {@code Paths.get()}. * This works just like {@code Paths.get()}.
@ -57,10 +57,30 @@ public final class PathUtils {
* a path against an existing one! * a path against an existing one!
*/ */
public static Path get(String first, String... more) { public static Path get(String first, String... more) {
return DEFAULT.getPath(first, more); return get(DEFAULT, first, more);
} }
/** /**
* Returns a {@code Path} from name components against the given
* {@code FileSystem}.
* <p>
* This works just like {@code Paths.get()}.
* Remember: just like {@code Paths.get()} this is NOT A STRING CONCATENATION
* UTILITY FUNCTION.
* <p>
* Remember: this should almost never be used. Usually resolve
* a path against an existing one!
*
* @param fs the given {@code FileSystem}
* @param first the first path component
* @param more the remaining path components
* @return a path
*/
public static Path get(FileSystem fs, String first, String... more) {
return fs.getPath(first, more);
}
/**
* Returns a {@code Path} from a URI * Returns a {@code Path} from a URI
* <p> * <p>
* This works just like {@code Paths.get()}. * This works just like {@code Paths.get()}.

View File

@ -38,6 +38,7 @@ import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.XContentType;
import java.io.IOException; import java.io.IOException;
import java.net.URI;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;

View File

@ -31,6 +31,7 @@ import java.net.MalformedURLException;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
import java.nio.file.FileStore; import java.nio.file.FileStore;
import java.nio.file.FileSystem;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
@ -108,28 +109,32 @@ public class Environment {
} }
public Environment(Settings settings) { public Environment(Settings settings) {
this(PathUtils.getDefaultFileSystem(), settings);
}
public Environment(FileSystem fs, Settings settings) {
this.settings = settings; this.settings = settings;
final Path homeFile; final Path homeFile;
if (PATH_HOME_SETTING.exists(settings)) { if (PATH_HOME_SETTING.exists(settings)) {
homeFile = PathUtils.get(cleanPath(PATH_HOME_SETTING.get(settings))); homeFile = PathUtils.get(fs, PATH_HOME_SETTING.get(settings));
} else { } else {
throw new IllegalStateException(PATH_HOME_SETTING.getKey() + " is not configured"); throw new IllegalStateException(PATH_HOME_SETTING.getKey() + " is not configured");
} }
if (PATH_CONF_SETTING.exists(settings)) { if (PATH_CONF_SETTING.exists(settings)) {
configFile = PathUtils.get(cleanPath(PATH_CONF_SETTING.get(settings))); configFile = PathUtils.get(fs, cleanPath(PATH_CONF_SETTING.get(settings)));
} else { } else {
configFile = homeFile.resolve("config"); configFile = homeFile.resolve("config");
} }
if (PATH_SCRIPTS_SETTING.exists(settings)) { if (PATH_SCRIPTS_SETTING.exists(settings)) {
scriptsFile = PathUtils.get(cleanPath(PATH_SCRIPTS_SETTING.get(settings))); scriptsFile = PathUtils.get(fs, cleanPath(PATH_SCRIPTS_SETTING.get(settings)));
} else { } else {
scriptsFile = configFile.resolve("scripts"); scriptsFile = configFile.resolve("scripts");
} }
if (PATH_PLUGINS_SETTING.exists(settings)) { if (PATH_PLUGINS_SETTING.exists(settings)) {
pluginsFile = PathUtils.get(cleanPath(PATH_PLUGINS_SETTING.get(settings))); pluginsFile = PathUtils.get(fs, cleanPath(PATH_PLUGINS_SETTING.get(settings)));
} else { } else {
pluginsFile = homeFile.resolve("plugins"); pluginsFile = homeFile.resolve("plugins");
} }
@ -139,7 +144,7 @@ public class Environment {
dataFiles = new Path[dataPaths.size()]; dataFiles = new Path[dataPaths.size()];
dataWithClusterFiles = new Path[dataPaths.size()]; dataWithClusterFiles = new Path[dataPaths.size()];
for (int i = 0; i < dataPaths.size(); i++) { for (int i = 0; i < dataPaths.size(); i++) {
dataFiles[i] = PathUtils.get(dataPaths.get(i)); dataFiles[i] = PathUtils.get(fs, dataPaths.get(i));
dataWithClusterFiles[i] = dataFiles[i].resolve(ClusterName.clusterNameFromSettings(settings).value()); dataWithClusterFiles[i] = dataFiles[i].resolve(ClusterName.clusterNameFromSettings(settings).value());
} }
} else { } else {

View File

@ -307,7 +307,7 @@ class InstallPluginCommand extends Command {
perms.add(PosixFilePermission.OTHERS_READ); perms.add(PosixFilePermission.OTHERS_READ);
perms.add(PosixFilePermission.OTHERS_EXECUTE); perms.add(PosixFilePermission.OTHERS_EXECUTE);
return Files.createTempDirectory(pluginsDir, ".installing-", PosixFilePermissions.asFileAttribute(perms)); return Files.createTempDirectory(pluginsDir, ".installing-", PosixFilePermissions.asFileAttribute(perms));
} catch (UnsupportedOperationException e) { } catch (IllegalArgumentException | UnsupportedOperationException e) {
return Files.createTempDirectory(pluginsDir, ".installing-"); return Files.createTempDirectory(pluginsDir, ".installing-");
} }
} }
@ -338,7 +338,7 @@ class InstallPluginCommand extends Command {
} }
/** check a candidate plugin for jar hell before installing it */ /** check a candidate plugin for jar hell before installing it */
private void jarHellCheck(Path candidate, Path pluginsDir, boolean isolated) throws Exception { void jarHellCheck(Path candidate, Path pluginsDir, boolean isolated) throws Exception {
// create list of current jars in classpath // create list of current jars in classpath
final List<URL> jars = new ArrayList<>(); final List<URL> jars = new ArrayList<>();
jars.addAll(Arrays.asList(JarHell.parseClassPath())); jars.addAll(Arrays.asList(JarHell.parseClassPath()));

View File

@ -21,6 +21,7 @@ package org.elasticsearch.node.internal;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.URI;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;

View File

@ -19,6 +19,19 @@
package org.elasticsearch.plugins; package org.elasticsearch.plugins;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import com.google.common.jimfs.Configuration;
import com.google.common.jimfs.Jimfs;
import org.apache.lucene.util.LuceneTestCase;
import org.elasticsearch.Version;
import org.elasticsearch.cli.MockTerminal;
import org.elasticsearch.cli.UserError;
import org.elasticsearch.common.io.PathUtils;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.PosixPermissionsResetter;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.MalformedURLException; import java.net.MalformedURLException;
@ -26,6 +39,7 @@ import java.net.URL;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.DirectoryStream; import java.nio.file.DirectoryStream;
import java.nio.file.FileAlreadyExistsException; import java.nio.file.FileAlreadyExistsException;
import java.nio.file.FileSystem;
import java.nio.file.FileVisitResult; import java.nio.file.FileVisitResult;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.NoSuchFileException; import java.nio.file.NoSuchFileException;
@ -36,44 +50,85 @@ import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.PosixFileAttributeView; import java.nio.file.attribute.PosixFileAttributeView;
import java.nio.file.attribute.PosixFileAttributes; import java.nio.file.attribute.PosixFileAttributes;
import java.nio.file.attribute.PosixFilePermission; import java.nio.file.attribute.PosixFilePermission;
import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream; import java.util.zip.ZipOutputStream;
import org.apache.lucene.util.LuceneTestCase; import static org.hamcrest.CoreMatchers.equalTo;
import org.elasticsearch.Version; import static org.hamcrest.Matchers.containsInAnyOrder;
import org.elasticsearch.cli.MockTerminal;
import org.elasticsearch.cli.UserError;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.PosixPermissionsResetter;
import org.junit.BeforeClass;
@LuceneTestCase.SuppressFileSystems("*") @LuceneTestCase.SuppressFileSystems("*")
public class InstallPluginCommandTests extends ESTestCase { public class InstallPluginCommandTests extends ESTestCase {
private static boolean isPosix; private final Function<String, Path> temp;
@BeforeClass private final FileSystem fs;
public static void checkPosix() throws IOException { private final boolean isPosix;
isPosix = Files.getFileAttributeView(createTempFile(), PosixFileAttributeView.class) != null; private final boolean isReal;
public InstallPluginCommandTests(FileSystem fs, Function<String, Path> temp) {
this.fs = fs;
this.temp = temp;
this.isPosix = fs.supportedFileAttributeViews().contains("posix");
this.isReal = fs == PathUtils.getDefaultFileSystem();
}
@ParametersFactory
public static Iterable<Object[]> parameters() {
class Parameter {
private final FileSystem fileSystem;
private final Function<String, Path> temp;
public Parameter(FileSystem fileSystem, Supplier<String> root) {
this(fileSystem, root, s -> {
try {
return Files.createTempDirectory(fileSystem.getPath(root.get()), s);
} catch (IOException e) {
throw new RuntimeException(e);
}
});
}
public Parameter(FileSystem fileSystem, Supplier<String> root, Function<String, Path> temp) {
this.fileSystem = fileSystem;
this.temp = temp;
}
}
List<Parameter> parameters = new ArrayList<>();
parameters.add(new Parameter(Jimfs.newFileSystem(Configuration.windows()), () -> "c:\\"));
parameters.add(new Parameter(Jimfs.newFileSystem(toPosix(Configuration.osX())), () -> "/"));
parameters.add(new Parameter(Jimfs.newFileSystem(toPosix(Configuration.unix())), () -> "/"));
parameters.add(new Parameter(PathUtils.getDefaultFileSystem(), () -> createTempDir().toString(), LuceneTestCase::createTempDir ));
return parameters.stream().map(p -> new Object[] { p.fileSystem, p.temp }).collect(Collectors.toList());
}
private static Configuration toPosix(Configuration configuration) {
return configuration.toBuilder().setAttributeViews("basic", "owner", "posix", "unix").build();
} }
/** Creates a test environment with bin, config and plugins directories. */ /** Creates a test environment with bin, config and plugins directories. */
static Environment createEnv() throws IOException { static Environment createEnv(FileSystem fs, Function<String, Path> temp) throws IOException {
Path home = createTempDir(); Path home = temp.apply("install-plugin-command-tests");
Files.createDirectories(home.resolve("bin")); Files.createDirectories(home.resolve("bin"));
Files.createFile(home.resolve("bin").resolve("elasticsearch")); Files.createFile(home.resolve("bin").resolve("elasticsearch"));
Files.createDirectories(home.resolve("config")); Files.createDirectories(home.resolve("config"));
Files.createFile(home.resolve("config").resolve("elasticsearch.yml")); Files.createFile(home.resolve("config").resolve("elasticsearch.yml"));
Files.createDirectories(home.resolve("plugins")); Path plugins = Files.createDirectories(home.resolve("plugins"));
assertTrue(Files.exists(plugins));
Settings settings = Settings.builder() Settings settings = Settings.builder()
.put("path.home", home) .put("path.home", home)
.build(); .build();
return new Environment(settings); return new Environment(fs, settings);
}
static Path createPluginDir(Function<String, Path> temp) throws IOException {
return temp.apply("pluginDir");
} }
/** creates a fake jar file with empty class files */ /** creates a fake jar file with empty class files */
@ -115,14 +170,40 @@ public class InstallPluginCommandTests extends ESTestCase {
} }
static MockTerminal installPlugin(String pluginUrl, Environment env) throws Exception { static MockTerminal installPlugin(String pluginUrl, Environment env) throws Exception {
return installPlugin(pluginUrl, env, false);
}
static MockTerminal installPlugin(String pluginUrl, Environment env, boolean jarHellCheck) throws Exception {
MockTerminal terminal = new MockTerminal(); MockTerminal terminal = new MockTerminal();
new InstallPluginCommand(env).execute(terminal, pluginUrl, true); new InstallPluginCommand(env) {
@Override
void jarHellCheck(Path candidate, Path pluginsDir, boolean isolated) throws Exception {
if (jarHellCheck) {
super.jarHellCheck(candidate, pluginsDir, isolated);
}
}
}.execute(terminal, pluginUrl, true);
return terminal; return terminal;
} }
void assertPlugin(String name, Path original, Environment env) throws IOException { void assertPlugin(String name, Path original, Environment env) throws IOException {
Path got = env.pluginsFile().resolve(name); Path got = env.pluginsFile().resolve(name);
assertTrue("dir " + name + " exists", Files.exists(got)); assertTrue("dir " + name + " exists", Files.exists(got));
if (isPosix) {
Set<PosixFilePermission> perms = Files.getPosixFilePermissions(got);
assertThat(
perms,
containsInAnyOrder(
PosixFilePermission.OWNER_READ,
PosixFilePermission.OWNER_WRITE,
PosixFilePermission.OWNER_EXECUTE,
PosixFilePermission.GROUP_READ,
PosixFilePermission.GROUP_EXECUTE,
PosixFilePermission.OTHERS_READ,
PosixFilePermission.OTHERS_EXECUTE));
}
assertTrue("jar was copied", Files.exists(got.resolve("plugin.jar"))); assertTrue("jar was copied", Files.exists(got.resolve("plugin.jar")));
assertFalse("bin was not copied", Files.exists(got.resolve("bin"))); assertFalse("bin was not copied", Files.exists(got.resolve("bin")));
assertFalse("config was not copied", Files.exists(got.resolve("config"))); assertFalse("config was not copied", Files.exists(got.resolve("config")));
@ -152,6 +233,16 @@ public class InstallPluginCommandTests extends ESTestCase {
Path configDir = env.configFile().resolve(name); Path configDir = env.configFile().resolve(name);
assertTrue("config dir exists", Files.exists(configDir)); assertTrue("config dir exists", Files.exists(configDir));
assertTrue("config is a dir", Files.isDirectory(configDir)); assertTrue("config is a dir", Files.isDirectory(configDir));
if (isPosix) {
Path configRoot = env.configFile();
PosixFileAttributes configAttributes =
Files.getFileAttributeView(configRoot, PosixFileAttributeView.class).readAttributes();
PosixFileAttributes attributes = Files.getFileAttributeView(configDir, PosixFileAttributeView.class).readAttributes();
assertThat(attributes.owner(), equalTo(configAttributes.owner()));
assertThat(attributes.group(), equalTo(configAttributes.group()));
}
try (DirectoryStream<Path> stream = Files.newDirectoryStream(configDir)) { try (DirectoryStream<Path> stream = Files.newDirectoryStream(configDir)) {
for (Path file : stream) { for (Path file : stream) {
assertFalse("not a dir", Files.isDirectory(file)); assertFalse("not a dir", Files.isDirectory(file));
@ -172,16 +263,16 @@ public class InstallPluginCommandTests extends ESTestCase {
} }
public void testSomethingWorks() throws Exception { public void testSomethingWorks() throws Exception {
Environment env = createEnv(); Environment env = createEnv(fs, temp);
Path pluginDir = createTempDir(); Path pluginDir = createPluginDir(temp);
String pluginZip = createPlugin("fake", pluginDir); String pluginZip = createPlugin("fake", pluginDir);
installPlugin(pluginZip, env); installPlugin(pluginZip, env);
assertPlugin("fake", pluginDir, env); assertPlugin("fake", pluginDir, env);
} }
public void testSpaceInUrl() throws Exception { public void testSpaceInUrl() throws Exception {
Environment env = createEnv(); Environment env = createEnv(fs, temp);
Path pluginDir = createTempDir(); Path pluginDir = createPluginDir(temp);
String pluginZip = createPlugin("fake", pluginDir); String pluginZip = createPlugin("fake", pluginDir);
Path pluginZipWithSpaces = createTempFile("foo bar", ".zip"); Path pluginZipWithSpaces = createTempFile("foo bar", ".zip");
try (InputStream in = new URL(pluginZip).openStream()) { try (InputStream in = new URL(pluginZip).openStream()) {
@ -192,28 +283,30 @@ public class InstallPluginCommandTests extends ESTestCase {
} }
public void testMalformedUrlNotMaven() throws Exception { public void testMalformedUrlNotMaven() throws Exception {
Environment env = createEnv(fs, temp);
// has two colons, so it appears similar to maven coordinates // has two colons, so it appears similar to maven coordinates
MalformedURLException e = expectThrows(MalformedURLException.class, () -> { MalformedURLException e = expectThrows(MalformedURLException.class, () -> {
installPlugin("://host:1234", createEnv()); installPlugin("://host:1234", env);
}); });
assertTrue(e.getMessage(), e.getMessage().contains("no protocol")); assertTrue(e.getMessage(), e.getMessage().contains("no protocol"));
} }
public void testPluginsDirMissing() throws Exception { public void testPluginsDirMissing() throws Exception {
Environment env = createEnv(); Environment env = createEnv(fs, temp);
Files.delete(env.pluginsFile()); Files.delete(env.pluginsFile());
Path pluginDir = createTempDir(); Path pluginDir = createPluginDir(temp);
String pluginZip = createPlugin("fake", pluginDir); String pluginZip = createPlugin("fake", pluginDir);
installPlugin(pluginZip, env); installPlugin(pluginZip, env);
assertPlugin("fake", pluginDir, env); assertPlugin("fake", pluginDir, env);
} }
public void testPluginsDirReadOnly() throws Exception { public void testPluginsDirReadOnly() throws Exception {
assumeTrue("posix filesystem", isPosix); assumeTrue("posix and filesystem", isPosix && isReal);
Environment env = createEnv(); Environment env = createEnv(fs, temp);
Path pluginDir = createPluginDir(temp);
try (PosixPermissionsResetter pluginsAttrs = new PosixPermissionsResetter(env.pluginsFile())) { try (PosixPermissionsResetter pluginsAttrs = new PosixPermissionsResetter(env.pluginsFile())) {
pluginsAttrs.setPermissions(new HashSet<>()); pluginsAttrs.setPermissions(new HashSet<>());
String pluginZip = createPlugin("fake", createTempDir()); String pluginZip = createPlugin("fake", pluginDir);
IOException e = expectThrows(IOException.class, () -> { IOException e = expectThrows(IOException.class, () -> {
installPlugin(pluginZip, env); installPlugin(pluginZip, env);
}); });
@ -223,8 +316,9 @@ public class InstallPluginCommandTests extends ESTestCase {
} }
public void testBuiltinModule() throws Exception { public void testBuiltinModule() throws Exception {
Environment env = createEnv(); Environment env = createEnv(fs, temp);
String pluginZip = createPlugin("lang-groovy", createTempDir()); Path pluginDir = createPluginDir(temp);
String pluginZip = createPlugin("lang-groovy", pluginDir);
UserError e = expectThrows(UserError.class, () -> { UserError e = expectThrows(UserError.class, () -> {
installPlugin(pluginZip, env); installPlugin(pluginZip, env);
}); });
@ -233,24 +327,26 @@ public class InstallPluginCommandTests extends ESTestCase {
} }
public void testJarHell() throws Exception { public void testJarHell() throws Exception {
Environment env = createEnv(); // jar hell test needs a real filesystem
Path pluginDir = createTempDir(); assumeTrue("real filesystem", isReal);
writeJar(pluginDir.resolve("other.jar"), "FakePlugin"); Environment environment = createEnv(fs, temp);
String pluginZip = createPlugin("fake", pluginDir); // adds plugin.jar with FakePlugin Path pluginDirectory = createPluginDir(temp);
writeJar(pluginDirectory.resolve("other.jar"), "FakePlugin");
String pluginZip = createPlugin("fake", pluginDirectory); // adds plugin.jar with FakePlugin
IllegalStateException e = expectThrows(IllegalStateException.class, () -> { IllegalStateException e = expectThrows(IllegalStateException.class, () -> {
installPlugin(pluginZip, env); installPlugin(pluginZip, environment, true);
}); });
assertTrue(e.getMessage(), e.getMessage().contains("jar hell")); assertTrue(e.getMessage(), e.getMessage().contains("jar hell"));
assertInstallCleaned(env); assertInstallCleaned(environment);
} }
public void testIsolatedPlugins() throws Exception { public void testIsolatedPlugins() throws Exception {
Environment env = createEnv(); Environment env = createEnv(fs, temp);
// these both share the same FakePlugin class // these both share the same FakePlugin class
Path pluginDir1 = createTempDir(); Path pluginDir1 = createPluginDir(temp);
String pluginZip1 = createPlugin("fake1", pluginDir1); String pluginZip1 = createPlugin("fake1", pluginDir1);
installPlugin(pluginZip1, env); installPlugin(pluginZip1, env);
Path pluginDir2 = createTempDir(); Path pluginDir2 = createPluginDir(temp);
String pluginZip2 = createPlugin("fake2", pluginDir2); String pluginZip2 = createPlugin("fake2", pluginDir2);
installPlugin(pluginZip2, env); installPlugin(pluginZip2, env);
assertPlugin("fake1", pluginDir1, env); assertPlugin("fake1", pluginDir1, env);
@ -258,8 +354,9 @@ public class InstallPluginCommandTests extends ESTestCase {
} }
public void testPurgatoryJarHell() throws Exception { public void testPurgatoryJarHell() throws Exception {
Environment env = createEnv(); assumeTrue("real filesystem", isReal);
Path pluginDir1 = createTempDir(); Environment environment = createEnv(fs, temp);
Path pluginDir1 = createPluginDir(temp);
PluginTestUtil.writeProperties(pluginDir1, PluginTestUtil.writeProperties(pluginDir1,
"description", "fake desc", "description", "fake desc",
"name", "fake1", "name", "fake1",
@ -270,9 +367,9 @@ public class InstallPluginCommandTests extends ESTestCase {
"isolated", "false"); "isolated", "false");
writeJar(pluginDir1.resolve("plugin.jar"), "FakePlugin"); writeJar(pluginDir1.resolve("plugin.jar"), "FakePlugin");
String pluginZip1 = writeZip(pluginDir1, "elasticsearch"); String pluginZip1 = writeZip(pluginDir1, "elasticsearch");
installPlugin(pluginZip1, env); installPlugin(pluginZip1, environment);
Path pluginDir2 = createTempDir(); Path pluginDir2 = createPluginDir(temp);
PluginTestUtil.writeProperties(pluginDir2, PluginTestUtil.writeProperties(pluginDir2,
"description", "fake desc", "description", "fake desc",
"name", "fake2", "name", "fake2",
@ -284,15 +381,16 @@ public class InstallPluginCommandTests extends ESTestCase {
writeJar(pluginDir2.resolve("plugin.jar"), "FakePlugin"); writeJar(pluginDir2.resolve("plugin.jar"), "FakePlugin");
String pluginZip2 = writeZip(pluginDir2, "elasticsearch"); String pluginZip2 = writeZip(pluginDir2, "elasticsearch");
IllegalStateException e = expectThrows(IllegalStateException.class, () -> { IllegalStateException e = expectThrows(IllegalStateException.class, () -> {
installPlugin(pluginZip2, env); installPlugin(pluginZip2, environment, true);
}); });
assertTrue(e.getMessage(), e.getMessage().contains("jar hell")); assertTrue(e.getMessage(), e.getMessage().contains("jar hell"));
assertInstallCleaned(env); assertInstallCleaned(environment);
} }
public void testExistingPlugin() throws Exception { public void testExistingPlugin() throws Exception {
Environment env = createEnv(); Environment env = createEnv(fs, temp);
String pluginZip = createPlugin("fake", createTempDir()); Path pluginDir = createPluginDir(temp);
String pluginZip = createPlugin("fake", pluginDir);
installPlugin(pluginZip, env); installPlugin(pluginZip, env);
UserError e = expectThrows(UserError.class, () -> { UserError e = expectThrows(UserError.class, () -> {
installPlugin(pluginZip, env); installPlugin(pluginZip, env);
@ -302,8 +400,8 @@ public class InstallPluginCommandTests extends ESTestCase {
} }
public void testBin() throws Exception { public void testBin() throws Exception {
Environment env = createEnv(); Environment env = createEnv(fs, temp);
Path pluginDir = createTempDir(); Path pluginDir = createPluginDir(temp);
Path binDir = pluginDir.resolve("bin"); Path binDir = pluginDir.resolve("bin");
Files.createDirectory(binDir); Files.createDirectory(binDir);
Files.createFile(binDir.resolve("somescript")); Files.createFile(binDir.resolve("somescript"));
@ -313,8 +411,8 @@ public class InstallPluginCommandTests extends ESTestCase {
} }
public void testBinNotDir() throws Exception { public void testBinNotDir() throws Exception {
Environment env = createEnv(); Environment env = createEnv(fs, temp);
Path pluginDir = createTempDir(); Path pluginDir = createPluginDir(temp);
Path binDir = pluginDir.resolve("bin"); Path binDir = pluginDir.resolve("bin");
Files.createFile(binDir); Files.createFile(binDir);
String pluginZip = createPlugin("fake", pluginDir); String pluginZip = createPlugin("fake", pluginDir);
@ -326,8 +424,8 @@ public class InstallPluginCommandTests extends ESTestCase {
} }
public void testBinContainsDir() throws Exception { public void testBinContainsDir() throws Exception {
Environment env = createEnv(); Environment env = createEnv(fs, temp);
Path pluginDir = createTempDir(); Path pluginDir = createPluginDir(temp);
Path dirInBinDir = pluginDir.resolve("bin").resolve("foo"); Path dirInBinDir = pluginDir.resolve("bin").resolve("foo");
Files.createDirectories(dirInBinDir); Files.createDirectories(dirInBinDir);
Files.createFile(dirInBinDir.resolve("somescript")); Files.createFile(dirInBinDir.resolve("somescript"));
@ -340,8 +438,8 @@ public class InstallPluginCommandTests extends ESTestCase {
} }
public void testBinConflict() throws Exception { public void testBinConflict() throws Exception {
Environment env = createEnv(); Environment env = createEnv(fs, temp);
Path pluginDir = createTempDir(); Path pluginDir = createPluginDir(temp);
Path binDir = pluginDir.resolve("bin"); Path binDir = pluginDir.resolve("bin");
Files.createDirectory(binDir); Files.createDirectory(binDir);
Files.createFile(binDir.resolve("somescript")); Files.createFile(binDir.resolve("somescript"));
@ -355,8 +453,8 @@ public class InstallPluginCommandTests extends ESTestCase {
public void testBinPermissions() throws Exception { public void testBinPermissions() throws Exception {
assumeTrue("posix filesystem", isPosix); assumeTrue("posix filesystem", isPosix);
Environment env = createEnv(); Environment env = createEnv(fs, temp);
Path pluginDir = createTempDir(); Path pluginDir = createPluginDir(temp);
Path binDir = pluginDir.resolve("bin"); Path binDir = pluginDir.resolve("bin");
Files.createDirectory(binDir); Files.createDirectory(binDir);
Files.createFile(binDir.resolve("somescript")); Files.createFile(binDir.resolve("somescript"));
@ -372,8 +470,8 @@ public class InstallPluginCommandTests extends ESTestCase {
} }
public void testConfig() throws Exception { public void testConfig() throws Exception {
Environment env = createEnv(); Environment env = createEnv(fs, temp);
Path pluginDir = createTempDir(); Path pluginDir = createPluginDir(temp);
Path configDir = pluginDir.resolve("config"); Path configDir = pluginDir.resolve("config");
Files.createDirectory(configDir); Files.createDirectory(configDir);
Files.createFile(configDir.resolve("custom.yaml")); Files.createFile(configDir.resolve("custom.yaml"));
@ -383,11 +481,11 @@ public class InstallPluginCommandTests extends ESTestCase {
} }
public void testExistingConfig() throws Exception { public void testExistingConfig() throws Exception {
Environment env = createEnv(); Environment env = createEnv(fs, temp);
Path envConfigDir = env.configFile().resolve("fake"); Path envConfigDir = env.configFile().resolve("fake");
Files.createDirectories(envConfigDir); Files.createDirectories(envConfigDir);
Files.write(envConfigDir.resolve("custom.yaml"), "existing config".getBytes(StandardCharsets.UTF_8)); Files.write(envConfigDir.resolve("custom.yaml"), "existing config".getBytes(StandardCharsets.UTF_8));
Path pluginDir = createTempDir(); Path pluginDir = createPluginDir(temp);
Path configDir = pluginDir.resolve("config"); Path configDir = pluginDir.resolve("config");
Files.createDirectory(configDir); Files.createDirectory(configDir);
Files.write(configDir.resolve("custom.yaml"), "new config".getBytes(StandardCharsets.UTF_8)); Files.write(configDir.resolve("custom.yaml"), "new config".getBytes(StandardCharsets.UTF_8));
@ -402,8 +500,8 @@ public class InstallPluginCommandTests extends ESTestCase {
} }
public void testConfigNotDir() throws Exception { public void testConfigNotDir() throws Exception {
Environment env = createEnv(); Environment env = createEnv(fs, temp);
Path pluginDir = createTempDir(); Path pluginDir = createPluginDir(temp);
Path configDir = pluginDir.resolve("config"); Path configDir = pluginDir.resolve("config");
Files.createFile(configDir); Files.createFile(configDir);
String pluginZip = createPlugin("fake", pluginDir); String pluginZip = createPlugin("fake", pluginDir);
@ -415,8 +513,8 @@ public class InstallPluginCommandTests extends ESTestCase {
} }
public void testConfigContainsDir() throws Exception { public void testConfigContainsDir() throws Exception {
Environment env = createEnv(); Environment env = createEnv(fs, temp);
Path pluginDir = createTempDir(); Path pluginDir = createPluginDir(temp);
Path dirInConfigDir = pluginDir.resolve("config").resolve("foo"); Path dirInConfigDir = pluginDir.resolve("config").resolve("foo");
Files.createDirectories(dirInConfigDir); Files.createDirectories(dirInConfigDir);
Files.createFile(dirInConfigDir.resolve("myconfig.yml")); Files.createFile(dirInConfigDir.resolve("myconfig.yml"));
@ -429,8 +527,8 @@ public class InstallPluginCommandTests extends ESTestCase {
} }
public void testConfigConflict() throws Exception { public void testConfigConflict() throws Exception {
Environment env = createEnv(); Environment env = createEnv(fs, temp);
Path pluginDir = createTempDir(); Path pluginDir = createPluginDir(temp);
Path configDir = pluginDir.resolve("config"); Path configDir = pluginDir.resolve("config");
Files.createDirectory(configDir); Files.createDirectory(configDir);
Files.createFile(configDir.resolve("myconfig.yml")); Files.createFile(configDir.resolve("myconfig.yml"));
@ -443,8 +541,8 @@ public class InstallPluginCommandTests extends ESTestCase {
} }
public void testMissingDescriptor() throws Exception { public void testMissingDescriptor() throws Exception {
Environment env = createEnv(); Environment env = createEnv(fs, temp);
Path pluginDir = createTempDir(); Path pluginDir = createPluginDir(temp);
Files.createFile(pluginDir.resolve("fake.yml")); Files.createFile(pluginDir.resolve("fake.yml"));
String pluginZip = writeZip(pluginDir, "elasticsearch"); String pluginZip = writeZip(pluginDir, "elasticsearch");
NoSuchFileException e = expectThrows(NoSuchFileException.class, () -> { NoSuchFileException e = expectThrows(NoSuchFileException.class, () -> {
@ -455,8 +553,8 @@ public class InstallPluginCommandTests extends ESTestCase {
} }
public void testMissingDirectory() throws Exception { public void testMissingDirectory() throws Exception {
Environment env = createEnv(); Environment env = createEnv(fs, temp);
Path pluginDir = createTempDir(); Path pluginDir = createPluginDir(temp);
Files.createFile(pluginDir.resolve(PluginInfo.ES_PLUGIN_PROPERTIES)); Files.createFile(pluginDir.resolve(PluginInfo.ES_PLUGIN_PROPERTIES));
String pluginZip = writeZip(pluginDir, null); String pluginZip = writeZip(pluginDir, null);
UserError e = expectThrows(UserError.class, () -> { UserError e = expectThrows(UserError.class, () -> {
@ -467,13 +565,14 @@ public class InstallPluginCommandTests extends ESTestCase {
} }
public void testZipRelativeOutsideEntryName() throws Exception { public void testZipRelativeOutsideEntryName() throws Exception {
Environment env = createEnv(fs, temp);
Path zip = createTempDir().resolve("broken.zip"); Path zip = createTempDir().resolve("broken.zip");
try (ZipOutputStream stream = new ZipOutputStream(Files.newOutputStream(zip))) { try (ZipOutputStream stream = new ZipOutputStream(Files.newOutputStream(zip))) {
stream.putNextEntry(new ZipEntry("elasticsearch/../blah")); stream.putNextEntry(new ZipEntry("elasticsearch/../blah"));
} }
String pluginZip = zip.toUri().toURL().toString(); String pluginZip = zip.toUri().toURL().toString();
IOException e = expectThrows(IOException.class, () -> { IOException e = expectThrows(IOException.class, () -> {
installPlugin(pluginZip, createEnv()); installPlugin(pluginZip, env);
}); });
assertTrue(e.getMessage(), e.getMessage().contains("resolving outside of plugin directory")); assertTrue(e.getMessage(), e.getMessage().contains("resolving outside of plugin directory"));
} }