From 4216fc9f642b495c35a733a84b2d6b7de43a0a45 Mon Sep 17 00:00:00 2001 From: Ryan Ernst Date: Sun, 11 Mar 2018 09:01:27 -0700 Subject: [PATCH] Plugins: Allow modules to spawn controllers (#28968) This commit makes the controller spawner also look under modules. It also fixes a bug in module security policy loading where the module is a meta plugin. --- .../bootstrap/SpawnerNoBootstrapTests.java | 51 +++++++++++-------- .../org/elasticsearch/bootstrap/Security.java | 10 +--- .../org/elasticsearch/bootstrap/Spawner.java | 16 +++--- 3 files changed, 42 insertions(+), 35 deletions(-) diff --git a/qa/no-bootstrap-tests/src/test/java/org/elasticsearch/bootstrap/SpawnerNoBootstrapTests.java b/qa/no-bootstrap-tests/src/test/java/org/elasticsearch/bootstrap/SpawnerNoBootstrapTests.java index e4e603dff95..9f895c44977 100644 --- a/qa/no-bootstrap-tests/src/test/java/org/elasticsearch/bootstrap/SpawnerNoBootstrapTests.java +++ b/qa/no-bootstrap-tests/src/test/java/org/elasticsearch/bootstrap/SpawnerNoBootstrapTests.java @@ -42,6 +42,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.function.Function; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; @@ -77,6 +78,7 @@ public class SpawnerNoBootstrapTests extends LuceneTestCase { // This plugin will NOT have a controller daemon Path plugin = environment.pluginsFile().resolve("a_plugin"); + Files.createDirectories(environment.modulesFile()); Files.createDirectories(plugin); PluginTestUtil.writePluginProperties( plugin, @@ -97,7 +99,12 @@ public class SpawnerNoBootstrapTests extends LuceneTestCase { /** * Two plugins - one with a controller daemon and one without. */ - public void testControllerSpawn() throws IOException, InterruptedException { + public void testControllerSpawn() throws Exception { + assertControllerSpawns(Environment::pluginsFile); + assertControllerSpawns(Environment::modulesFile); + } + + private void assertControllerSpawns(Function pluginsDirFinder) throws Exception { /* * On Windows you can not directly run a batch file - you have to run cmd.exe with the batch * file as an argument and that's out of the remit of the controller daemon process spawner. @@ -112,32 +119,34 @@ public class SpawnerNoBootstrapTests extends LuceneTestCase { Environment environment = TestEnvironment.newEnvironment(settings); // this plugin will have a controller daemon - Path plugin = environment.pluginsFile().resolve("test_plugin"); + Path plugin = pluginsDirFinder.apply(environment).resolve("test_plugin"); + Files.createDirectories(environment.modulesFile()); + Files.createDirectories(environment.pluginsFile()); Files.createDirectories(plugin); PluginTestUtil.writePluginProperties( - plugin, - "description", "test_plugin", - "version", Version.CURRENT.toString(), - "elasticsearch.version", Version.CURRENT.toString(), - "name", "test_plugin", - "java.version", "1.8", - "classname", "TestPlugin", - "has.native.controller", "true"); + plugin, + "description", "test_plugin", + "version", Version.CURRENT.toString(), + "elasticsearch.version", Version.CURRENT.toString(), + "name", "test_plugin", + "java.version", "1.8", + "classname", "TestPlugin", + "has.native.controller", "true"); Path controllerProgram = Platforms.nativeControllerPath(plugin); createControllerProgram(controllerProgram); // this plugin will not have a controller daemon - Path otherPlugin = environment.pluginsFile().resolve("other_plugin"); + Path otherPlugin = pluginsDirFinder.apply(environment).resolve("other_plugin"); Files.createDirectories(otherPlugin); PluginTestUtil.writePluginProperties( - otherPlugin, - "description", "other_plugin", - "version", Version.CURRENT.toString(), - "elasticsearch.version", Version.CURRENT.toString(), - "name", "other_plugin", - "java.version", "1.8", - "classname", "OtherPlugin", - "has.native.controller", "false"); + otherPlugin, + "description", "other_plugin", + "version", Version.CURRENT.toString(), + "elasticsearch.version", Version.CURRENT.toString(), + "name", "other_plugin", + "java.version", "1.8", + "classname", "OtherPlugin", + "has.native.controller", "false"); Spawner spawner = new Spawner(); spawner.spawnNativePluginControllers(environment); @@ -150,7 +159,7 @@ public class SpawnerNoBootstrapTests extends LuceneTestCase { assertThat(processes, hasSize(1)); Process process = processes.get(0); final InputStreamReader in = - new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8); + new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8); try (BufferedReader stdoutReader = new BufferedReader(in)) { String line = stdoutReader.readLine(); assertEquals("I am alive", line); @@ -181,6 +190,7 @@ public class SpawnerNoBootstrapTests extends LuceneTestCase { Environment environment = TestEnvironment.newEnvironment(settings); Path metaPlugin = environment.pluginsFile().resolve("meta_plugin"); + Files.createDirectories(environment.modulesFile()); Files.createDirectories(metaPlugin); PluginTestUtil.writeMetaPluginProperties( metaPlugin, @@ -279,6 +289,7 @@ public class SpawnerNoBootstrapTests extends LuceneTestCase { final Environment environment = TestEnvironment.newEnvironment(settings); + Files.createDirectories(environment.modulesFile()); Files.createDirectories(environment.pluginsFile()); final Path desktopServicesStore = environment.pluginsFile().resolve(".DS_Store"); diff --git a/server/src/main/java/org/elasticsearch/bootstrap/Security.java b/server/src/main/java/org/elasticsearch/bootstrap/Security.java index 57b14138307..9f2790c94cc 100644 --- a/server/src/main/java/org/elasticsearch/bootstrap/Security.java +++ b/server/src/main/java/org/elasticsearch/bootstrap/Security.java @@ -163,16 +163,8 @@ final class Security { Map map = new HashMap<>(); // collect up set of plugins and modules by listing directories. Set pluginsAndModules = new LinkedHashSet<>(PluginsService.findPluginDirs(environment.pluginsFile())); + pluginsAndModules.addAll(PluginsService.findPluginDirs(environment.modulesFile())); - if (Files.exists(environment.modulesFile())) { - try (DirectoryStream stream = Files.newDirectoryStream(environment.modulesFile())) { - for (Path module : stream) { - if (pluginsAndModules.add(module) == false) { - throw new IllegalStateException("duplicate module: " + module); - } - } - } - } // now process each one for (Path plugin : pluginsAndModules) { Path policyFile = plugin.resolve(PluginInfo.ES_PLUGIN_POLICY); diff --git a/server/src/main/java/org/elasticsearch/bootstrap/Spawner.java b/server/src/main/java/org/elasticsearch/bootstrap/Spawner.java index dcaad3c39dd..08731522a31 100644 --- a/server/src/main/java/org/elasticsearch/bootstrap/Spawner.java +++ b/server/src/main/java/org/elasticsearch/bootstrap/Spawner.java @@ -63,15 +63,20 @@ final class Spawner implements Closeable { if (!spawned.compareAndSet(false, true)) { throw new IllegalStateException("native controllers already spawned"); } - final Path pluginsFile = environment.pluginsFile(); - if (!Files.exists(pluginsFile)) { - throw new IllegalStateException("plugins directory [" + pluginsFile + "] not found"); + spawnControllers(environment.pluginsFile(), "plugins", environment.tmpFile()); + spawnControllers(environment.modulesFile(), "modules", environment.tmpFile()); + } + + /** Spawn controllers in plugins found within the given directory. */ + private void spawnControllers(Path pluginsDir, String type, Path tmpDir) throws IOException { + if (!Files.exists(pluginsDir)) { + throw new IllegalStateException(type + " directory [" + pluginsDir + "] not found"); } /* * For each plugin, attempt to spawn the controller daemon. Silently ignore any plugin that * don't include a controller for the correct platform. */ - List paths = PluginsService.findPluginDirs(pluginsFile); + List paths = PluginsService.findPluginDirs(pluginsDir); for (Path plugin : paths) { final PluginInfo info = PluginInfo.readFromProperties(plugin); final Path spawnPath = Platforms.nativeControllerPath(plugin); @@ -85,8 +90,7 @@ final class Spawner implements Closeable { plugin.getFileName()); throw new IllegalArgumentException(message); } - final Process process = - spawnNativePluginController(spawnPath, environment.tmpFile()); + final Process process = spawnNativePluginController(spawnPath, tmpDir); processes.add(process); } }