Marvel: Add tribe nodes support

This commit enable tribe nodes support for Marvel. It avoid ElasticsearchSecurityException when a tribe node is connected to a cluster that has been configured for both Shield and Marvel by loading the MarvelShieldIntegration support on tribe node even if marvel.enabled is set to false. It also allows tribe nodes to be monitored using Marvel with their own marvel settings.

closes elastic/elasticsearch#1088

Original commit: elastic/x-pack-elasticsearch@e0401c1288
This commit is contained in:
Tanguy Leroux 2015-12-16 12:09:15 +01:00
parent d3ced7161b
commit a931e4e0b8
3 changed files with 59 additions and 22 deletions

View File

@ -29,9 +29,11 @@ import org.elasticsearch.shield.authz.AuthorizationModule;
import org.elasticsearch.tribe.TribeService;
import org.elasticsearch.xpack.XPackPlugin;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public class MarvelPlugin extends Plugin {
@ -58,22 +60,29 @@ public class MarvelPlugin extends Plugin {
return "Elasticsearch Marvel";
}
public boolean isEnabled() {
boolean isEnabled() {
return enabled;
}
@Override
public Collection<Module> nodeModules() {
if (!enabled) {
return Collections.emptyList();
List<Module> modules = new ArrayList<>();
// Always load the security integration for tribe nodes.
// This is useful if the tribe node is connected to a
// protected monitored cluster: __marvel_user operations must be allowed.
if (enabled || isTribeNode(settings) || isTribeClientNode(settings)) {
modules.add(new MarvelShieldModule(settings));
}
return Arrays.<Module>asList(
new MarvelModule(),
new LicenseModule(),
new CollectorModule(),
new ExporterModule(settings),
new MarvelShieldModule(settings),
new RendererModule());
if (enabled) {
modules.add(new MarvelModule());
modules.add(new LicenseModule());
modules.add(new CollectorModule());
modules.add(new ExporterModule(settings));
modules.add(new RendererModule());
}
return Collections.unmodifiableList(modules);
}
@Override
@ -85,17 +94,29 @@ public class MarvelPlugin extends Plugin {
}
public static boolean marvelEnabled(Settings settings) {
String tribe = settings.get(TribeService.TRIBE_NAME);
if (tribe != null) {
logger.trace("marvel cannot be started on tribe node [{}]", tribe);
return false;
}
if (!"node".equals(settings.get(Client.CLIENT_TYPE_SETTING))) {
logger.trace("marvel cannot be started on a transport client");
return false;
}
return settings.getAsBoolean(ENABLED, true);
// By default, marvel is disabled on tribe nodes
return settings.getAsBoolean(ENABLED, !isTribeNode(settings) && !isTribeClientNode(settings));
}
static boolean isTribeNode(Settings settings) {
if (settings.getGroups("tribe", true).isEmpty() == false) {
logger.trace("detecting tribe node");
return true;
}
return false;
}
static boolean isTribeClientNode(Settings settings) {
String tribeName = settings.get(TribeService.TRIBE_NAME);
if (tribeName != null) {
logger.trace("detecting tribe client node [{}]", tribeName);
return true;
}
return false;
}
// NOTE: The fact this signature takes a module is a hack, and effectively like the previous
@ -103,7 +124,7 @@ public class MarvelPlugin extends Plugin {
// We need to avoid trying to load the AuthorizationModule class unless we know shield integration
// is enabled. This is a temporary solution until inter-plugin-communication can be worked out.
public void onModule(Module module) {
if (enabled && MarvelShieldIntegration.enabled(settings) && module instanceof AuthorizationModule) {
if (MarvelShieldIntegration.enabled(settings) && module instanceof AuthorizationModule) {
((AuthorizationModule)module).registerReservedRole(InternalMarvelUser.ROLE);
}
}

View File

@ -7,23 +7,28 @@ package org.elasticsearch.marvel.shield;
import org.elasticsearch.common.inject.AbstractModule;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.marvel.MarvelPlugin;
/**
*
*/
public class MarvelShieldModule extends AbstractModule {
private final boolean enabled;
private final boolean shieldEnabled;
private final boolean marvelEnabled;
public MarvelShieldModule(Settings settings) {
this.enabled = MarvelShieldIntegration.enabled(settings);
this.shieldEnabled = MarvelShieldIntegration.enabled(settings);
this.marvelEnabled = MarvelPlugin.marvelEnabled(settings);;
}
@Override
protected void configure() {
bind(MarvelShieldIntegration.class).asEagerSingleton();
bind(SecuredClient.class).asEagerSingleton();
if (enabled) {
if (marvelEnabled) {
bind(SecuredClient.class).asEagerSingleton();
}
if (shieldEnabled) {
bind(MarvelSettingsFilter.Shield.class).asEagerSingleton();
bind(MarvelSettingsFilter.class).to(MarvelSettingsFilter.Shield.class);
} else {

View File

@ -9,6 +9,8 @@ import org.elasticsearch.action.admin.cluster.node.info.NodeInfo;
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.marvel.agent.AgentService;
import org.elasticsearch.marvel.agent.settings.MarvelSettings;
import org.elasticsearch.marvel.shield.MarvelShieldIntegration;
import org.elasticsearch.marvel.test.MarvelIntegTestCase;
import org.elasticsearch.plugins.PluginInfo;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
@ -24,6 +26,7 @@ public class MarvelPluginTests extends MarvelIntegTestCase {
protected Settings nodeSettings(int nodeOrdinal) {
return Settings.builder()
.put(super.nodeSettings(nodeOrdinal))
.put(MarvelSettings.INTERVAL_SETTING.getKey(), "-1")
.build();
}
@ -39,10 +42,18 @@ public class MarvelPluginTests extends MarvelIntegTestCase {
assertServiceIsNotBound(AgentService.class);
}
public void testMarvelEnabledOnTribeNode() {
internalCluster().startNode(Settings.builder().put(MarvelPlugin.ENABLED, true).put(TribeService.TRIBE_NAME, "t1").build());
assertPluginIsLoaded();
assertServiceIsBound(AgentService.class);
assertServiceIsBound(MarvelShieldIntegration.class);
}
public void testMarvelDisabledOnTribeNode() {
internalCluster().startNode(Settings.builder().put(TribeService.TRIBE_NAME, "t1").build());
assertPluginIsLoaded();
assertServiceIsNotBound(AgentService.class);
assertServiceIsBound(MarvelShieldIntegration.class);
}
private void assertPluginIsLoaded() {