Allocation: add support for filtering by transport IP address

Allocation filtering by IP only works today using the node host address. But in some cases, you might want to filter using the publish address which could be different.
This commit is contained in:
David Pilato 2014-12-06 08:25:29 +01:00
parent 30ca6d3970
commit 35049a05c3
3 changed files with 217 additions and 21 deletions

View File

@ -19,9 +19,12 @@
package org.elasticsearch.cluster.node;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.network.NetworkAddress;
import org.elasticsearch.common.regex.Regex;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import java.util.HashMap;
import java.util.Map;
@ -64,21 +67,72 @@ public class DiscoveryNodeFilters {
this.filters = filters;
}
private boolean matchByIP(String[] values, @Nullable String hostIp, @Nullable String publishIp) {
for (String value : values) {
boolean matchIp = Regex.simpleMatch(value, hostIp) || Regex.simpleMatch(value, publishIp);
if (matchIp) {
return matchIp;
}
}
return false;
}
public boolean match(DiscoveryNode node) {
for (Map.Entry<String, String[]> entry : filters.entrySet()) {
String attr = entry.getKey();
String[] values = entry.getValue();
if ("_ip".equals(attr)) {
for (String value : values) {
if (Regex.simpleMatch(value, node.getHostAddress())) {
if (opType == OpType.OR) {
return true;
}
} else {
if (opType == OpType.AND) {
return false;
}
// We check both the host_ip or the publish_ip
String publishAddress = null;
if (node.address() instanceof InetSocketTransportAddress) {
publishAddress = NetworkAddress.format(((InetSocketTransportAddress) node.address()).address().getAddress());
}
boolean match = matchByIP(values, node.getHostAddress(), publishAddress);
if (opType == OpType.AND) {
if (match) {
// If we match, we can check to the next filter
continue;
}
return false;
}
if (match && opType == OpType.OR) {
return true;
}
} else if ("_host_ip".equals(attr)) {
// We check explicitly only the host_ip
boolean match = matchByIP(values, node.getHostAddress(), null);
if (opType == OpType.AND) {
if (match) {
// If we match, we can check to the next filter
continue;
}
return false;
}
if (match && opType == OpType.OR) {
return true;
}
} else if ("_publish_ip".equals(attr)) {
// We check explicitly only the publish_ip
String address = null;
if (node.address() instanceof InetSocketTransportAddress) {
address = NetworkAddress.format(((InetSocketTransportAddress) node.address()).address().getAddress());
}
boolean match = matchByIP(values, address, null);
if (opType == OpType.AND) {
if (match) {
// If we match, we can check to the next filter
continue;
}
return false;
}
if (match && opType == OpType.OR) {
return true;
}
} else if ("_host".equals(attr)) {
for (String value : values) {
@ -171,7 +225,7 @@ public class DiscoveryNodeFilters {
for (String value : values) {
sb.append(value);
if (valueCount > 1) {
sb.append(" " + opType.toString() + " ");
sb.append(" ").append(opType.toString()).append(" ");
}
valueCount--;
}

View File

@ -23,18 +23,38 @@ import com.google.common.collect.ImmutableMap;
import org.elasticsearch.Version;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.DummyTransportAddress;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.test.ESTestCase;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static org.elasticsearch.cluster.node.DiscoveryNodeFilters.OpType.AND;
import static org.elasticsearch.cluster.node.DiscoveryNodeFilters.OpType.OR;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
/**
*/
public class DiscoveryNodeFiltersTests extends ESTestCase {
private static InetSocketTransportAddress localAddress;
@BeforeClass
public static void createLocalAddress() throws UnknownHostException {
localAddress = new InetSocketTransportAddress(InetAddress.getByName("192.1.1.54"), 9999);
}
@AfterClass
public static void releaseLocalAddress() {
localAddress = null;
}
@Test
public void nameMatch() {
Settings settings = Settings.settingsBuilder()
@ -65,10 +85,10 @@ public class DiscoveryNodeFiltersTests extends ESTestCase {
@Test
public void idOrNameMatch() {
Settings settings = Settings.settingsBuilder()
Settings settings = shuffleSettings(Settings.settingsBuilder()
.put("xxx._id", "id1,blah")
.put("xxx.name", "blah,name2")
.build();
.build());
DiscoveryNodeFilters filters = DiscoveryNodeFilters.buildFromSettings(OR, "xxx.", settings);
DiscoveryNode node = new DiscoveryNode("name1", "id1", DummyTransportAddress.INSTANCE, ImmutableMap.<String, String>of(), Version.CURRENT);
@ -83,22 +103,22 @@ public class DiscoveryNodeFiltersTests extends ESTestCase {
@Test
public void tagAndGroupMatch() {
Settings settings = Settings.settingsBuilder()
Settings settings = shuffleSettings(Settings.settingsBuilder()
.put("xxx.tag", "A")
.put("xxx.group", "B")
.build();
.build());
DiscoveryNodeFilters filters = DiscoveryNodeFilters.buildFromSettings(AND, "xxx.", settings);
DiscoveryNode node = new DiscoveryNode("name1", "id1", DummyTransportAddress.INSTANCE,
ImmutableMap.<String, String>of("tag", "A", "group", "B"), Version.CURRENT);
ImmutableMap.of("tag", "A", "group", "B"), Version.CURRENT);
assertThat(filters.match(node), equalTo(true));
node = new DiscoveryNode("name2", "id2", DummyTransportAddress.INSTANCE,
ImmutableMap.<String, String>of("tag", "A", "group", "B", "name", "X"), Version.CURRENT);
ImmutableMap.of("tag", "A", "group", "B", "name", "X"), Version.CURRENT);
assertThat(filters.match(node), equalTo(true));
node = new DiscoveryNode("name3", "id3", DummyTransportAddress.INSTANCE,
ImmutableMap.<String, String>of("tag", "A", "group", "F", "name", "X"), Version.CURRENT);
ImmutableMap.of("tag", "A", "group", "F", "name", "X"), Version.CURRENT);
assertThat(filters.match(node), equalTo(false));
node = new DiscoveryNode("name4", "id4", DummyTransportAddress.INSTANCE, ImmutableMap.<String, String>of(), Version.CURRENT);
@ -115,4 +135,124 @@ public class DiscoveryNodeFiltersTests extends ESTestCase {
DiscoveryNode node = new DiscoveryNode("name1", "id1", DummyTransportAddress.INSTANCE, ImmutableMap.<String, String>of(), Version.CURRENT);
assertThat(filters.match(node), equalTo(true));
}
@Test
public void ipBindFilteringMatchingAnd() {
Settings settings = shuffleSettings(Settings.settingsBuilder()
.put("xxx.tag", "A")
.put("xxx." + randomFrom("_ip", "_host_ip", "_publish_ip"), "192.1.1.54")
.build());
DiscoveryNodeFilters filters = DiscoveryNodeFilters.buildFromSettings(AND, "xxx.", settings);
DiscoveryNode node = new DiscoveryNode("", "", "", "192.1.1.54", localAddress, ImmutableMap.of("tag", "A"), null);
assertThat(filters.match(node), equalTo(true));
}
@Test
public void ipBindFilteringNotMatching() {
Settings settings = shuffleSettings(Settings.settingsBuilder()
.put("xxx.tag", "B")
.put("xxx." + randomFrom("_ip", "_host_ip", "_publish_ip"), "192.1.1.54")
.build());
DiscoveryNodeFilters filters = DiscoveryNodeFilters.buildFromSettings(AND, "xxx.", settings);
DiscoveryNode node = new DiscoveryNode("", "", "", "192.1.1.54", localAddress, ImmutableMap.of("tag", "A"), null);
assertThat(filters.match(node), equalTo(false));
}
@Test
public void ipBindFilteringNotMatchingAnd() {
Settings settings = shuffleSettings(Settings.settingsBuilder()
.put("xxx.tag", "A")
.put("xxx." + randomFrom("_ip", "_host_ip", "_publish_ip"), "8.8.8.8")
.build());
DiscoveryNodeFilters filters = DiscoveryNodeFilters.buildFromSettings(AND, "xxx.", settings);
DiscoveryNode node = new DiscoveryNode("", "", "", "192.1.1.54", localAddress, ImmutableMap.of("tag", "A"), null);
assertThat(filters.match(node), equalTo(false));
}
@Test
public void ipBindFilteringMatchingOr() {
Settings settings = shuffleSettings(Settings.settingsBuilder()
.put("xxx." + randomFrom("_ip", "_host_ip", "_publish_ip"), "192.1.1.54")
.put("xxx.tag", "A")
.build());
DiscoveryNodeFilters filters = DiscoveryNodeFilters.buildFromSettings(OR, "xxx.", settings);
DiscoveryNode node = new DiscoveryNode("", "", "", "192.1.1.54", localAddress, ImmutableMap.of("tag", "A"), null);
assertThat(filters.match(node), equalTo(true));
}
@Test
public void ipBindFilteringNotMatchingOr() {
Settings settings = shuffleSettings(Settings.settingsBuilder()
.put("xxx.tag", "A")
.put("xxx." + randomFrom("_ip", "_host_ip", "_publish_ip"), "8.8.8.8")
.build());
DiscoveryNodeFilters filters = DiscoveryNodeFilters.buildFromSettings(OR, "xxx.", settings);
DiscoveryNode node = new DiscoveryNode("", "", "", "192.1.1.54", localAddress, ImmutableMap.of("tag", "A"), null);
assertThat(filters.match(node), equalTo(true));
}
@Test
public void ipPublishFilteringMatchingAnd() {
Settings settings = shuffleSettings(Settings.settingsBuilder()
.put("xxx.tag", "A")
.put("xxx._publish_ip", "192.1.1.54")
.build());
DiscoveryNodeFilters filters = DiscoveryNodeFilters.buildFromSettings(AND, "xxx.", settings);
DiscoveryNode node = new DiscoveryNode("", "", "", "192.1.1.54", localAddress, ImmutableMap.of("tag", "A"), null);
assertThat(filters.match(node), equalTo(true));
}
@Test
public void ipPublishFilteringNotMatchingAnd() {
Settings settings = shuffleSettings(Settings.settingsBuilder()
.put("xxx.tag", "A")
.put("xxx._publish_ip", "8.8.8.8")
.build());
DiscoveryNodeFilters filters = DiscoveryNodeFilters.buildFromSettings(AND, "xxx.", settings);
DiscoveryNode node = new DiscoveryNode("", "", "", "192.1.1.54", localAddress, ImmutableMap.of("tag", "A"), null);
assertThat(filters.match(node), equalTo(false));
}
@Test
public void ipPublishFilteringMatchingOr() {
Settings settings = shuffleSettings(Settings.settingsBuilder()
.put("xxx._publish_ip", "192.1.1.54")
.put("xxx.tag", "A")
.build());
DiscoveryNodeFilters filters = DiscoveryNodeFilters.buildFromSettings(OR, "xxx.", settings);
DiscoveryNode node = new DiscoveryNode("", "", "", "192.1.1.54", localAddress, ImmutableMap.of("tag", "A"), null);
assertThat(filters.match(node), equalTo(true));
}
@Test
public void ipPublishFilteringNotMatchingOr() {
Settings settings = shuffleSettings(Settings.settingsBuilder()
.put("xxx.tag", "A")
.put("xxx._publish_ip", "8.8.8.8")
.build());
DiscoveryNodeFilters filters = DiscoveryNodeFilters.buildFromSettings(OR, "xxx.", settings);
DiscoveryNode node = new DiscoveryNode("", "", "", "192.1.1.54", localAddress, ImmutableMap.of("tag", "A"), null);
assertThat(filters.match(node), equalTo(true));
}
private Settings shuffleSettings(Settings source) {
Settings.Builder settings = Settings.settingsBuilder();
List<String> keys = new ArrayList(source.getAsMap().keySet());
Collections.shuffle(keys, getRandom());
for (String o : keys) {
settings.put(o, source.getAsMap().get(o));
}
return settings.build();
}
}

View File

@ -81,9 +81,11 @@ one set of nodes to another:
These special attributes are also supported:
[horizontal]
`_name`:: Match nodes by node name
`_ip`:: Match nodes by IP address (the IP address associated with the hostname)
`_host`:: Match nodes by hostname
`_name`:: Match nodes by node name
`_host_ip`:: Match nodes by host IP address (IP associated with hostname)
`_publish_ip`:: Match nodes by publish IP address
`_ip`:: Match either `_host_ip` or `_publish_ip`
`_host`:: Match nodes by hostname
All attribute values can be specified with wildcards, eg: