diff --git a/core/src/main/java/org/elasticsearch/cluster/node/DiscoveryNodeFilters.java b/core/src/main/java/org/elasticsearch/cluster/node/DiscoveryNodeFilters.java index 2ac98dcea13..ab7da4bfc56 100644 --- a/core/src/main/java/org/elasticsearch/cluster/node/DiscoveryNodeFilters.java +++ b/core/src/main/java/org/elasticsearch/cluster/node/DiscoveryNodeFilters.java @@ -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 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--; } diff --git a/core/src/test/java/org/elasticsearch/cluster/node/DiscoveryNodeFiltersTests.java b/core/src/test/java/org/elasticsearch/cluster/node/DiscoveryNodeFiltersTests.java index 141d983ab92..b37495e3285 100644 --- a/core/src/test/java/org/elasticsearch/cluster/node/DiscoveryNodeFiltersTests.java +++ b/core/src/test/java/org/elasticsearch/cluster/node/DiscoveryNodeFiltersTests.java @@ -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.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.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.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.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.of(), Version.CURRENT); @@ -115,4 +135,124 @@ public class DiscoveryNodeFiltersTests extends ESTestCase { DiscoveryNode node = new DiscoveryNode("name1", "id1", DummyTransportAddress.INSTANCE, ImmutableMap.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 keys = new ArrayList(source.getAsMap().keySet()); + Collections.shuffle(keys, getRandom()); + for (String o : keys) { + settings.put(o, source.getAsMap().get(o)); + } + return settings.build(); + } + + } diff --git a/docs/reference/index-modules/allocation/filtering.asciidoc b/docs/reference/index-modules/allocation/filtering.asciidoc index 99fd1dc7e2e..4c2b7f41a87 100644 --- a/docs/reference/index-modules/allocation/filtering.asciidoc +++ b/docs/reference/index-modules/allocation/filtering.asciidoc @@ -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: