├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE.txt ├── README.md ├── build.gradle └── src ├── main ├── assemblies │ └── plugin.xml ├── java │ └── org │ │ └── elasticsearch │ │ ├── discovery │ │ ├── srv │ │ │ ├── SrvDiscovery.java │ │ │ ├── SrvDiscoveryModule.java │ │ │ └── SrvUnicastHostsProvider.java │ │ └── srvtest │ │ │ ├── Constants.java │ │ │ ├── SrvtestDiscovery.java │ │ │ ├── SrvtestDiscoveryModule.java │ │ │ └── SrvtestUnicastHostsProvider.java │ │ └── plugin │ │ └── discovery │ │ └── SrvDiscoveryPlugin.java └── resources │ └── es-plugin.properties └── test ├── java └── org │ └── elasticsearch │ └── discovery │ └── srv │ └── SrvDiscoveryIntegrationTest.java └── log4j.xml /.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/github/elasticsearch-srv-discovery/923a5e4d15dacf76d112a5771360e829b258aac0/.gitignore -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | before_cache: 3 | - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock 4 | cache: 5 | directories: 6 | - $HOME/.gradle/caches/ 7 | - $HOME/.gradle/wrapper/ 8 | notifications: 9 | email: false 10 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.5.1 (2015-12-07) 2 | - Fix bug where TCP protocol was never set 3 | - Fix bug where protocol defaulted to UDP when no servers were specified 4 | 5 | ## 1.5.0 (2015-11-17) 6 | - Release first version 7 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 GitHub 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SRV Discovery Plugin for Elasticsearch 2 | ====================================== 3 | 4 | Use SRV records for Elasticsearch discovery, like the ones 5 | [Consul](https://consul.io) provides. 6 | 7 | Looking for a plugin that uses the Consul API directly? Check out 8 | [lithiumtech/elasticsearch-consul-discovery](https://github.com/lithiumtech/elasticsearch-consul-discovery). 9 | 10 | ## Installation 11 | 12 | Based on the version of Elasticsearch that you're running, pick the compatible plugin version (e.g. `1.5.1`), then run this command: 13 | 14 | ```bash 15 | bin/plugin install srv-discovery --url https://github.com/github/elasticsearch-srv-discovery/releases/download/1.5.1/elasticsearch-srv-discovery-1.5.1.zip 16 | ``` 17 | 18 | Verify that the plugin was installed: 19 | 20 | ``` 21 | $ bin/plugin -l 22 | Installed plugins: 23 | - srv-discovery 24 | 25 | $ curl localhost:9200/_cat/plugins?v 26 | name component version type url 27 | Pluto srv-discovery ... j 28 | ``` 29 | 30 | ## Compatibility 31 | 32 | The SRV Discovery plugin is known to be compatible with these versions of Elasticsearch: 33 | 34 | Elasticsearch|SRV Discovery plugin 35 | ---|--- 36 | 1.7.3|1.5.1 37 | 1.7.2|1.5.1 38 | 1.7.1|1.5.1 39 | 1.7.0|1.5.1 40 | 1.6.2|1.5.1 41 | 1.6.1|1.5.1 42 | 1.6.0|1.5.1 43 | 1.5.2|1.5.1 44 | 1.5.1|1.5.1 45 | 1.5.0|1.5.1 46 | 47 | ## Configuration 48 | 49 | Key|Example|Description 50 | ---|---|--- 51 | `discovery.srv.query`|`elasticsearch-9300.service.consul`|The query string to use when querying for SRV records. 52 | `discovery.srv.servers`|`127.0.0.1:8600`|DNS Servers to contact. Can be an array or a comma-delimited string. Port numbers are optional. 53 | `discovery.srv.protocol`|`tcp`|Which protocol to use. Options are `tcp` and `udp`. Default is `tcp`. 54 | 55 | Note: Consul will return maximum 3 records when using UDP queries. All records are returned when using TCP. 56 | 57 | ### Simple Example 58 | ```yaml 59 | discovery: 60 | type: srv 61 | srv: 62 | query: elasticsearch-9300.service.consul 63 | ``` 64 | 65 | ### Complex Example 66 | ```yaml 67 | discovery: 68 | type: srv 69 | srv: 70 | query: elasticsearch-9300.service.consul 71 | protocol: tcp 72 | servers: 73 | - 127.0.0.1:8600 74 | - 192.168.1.1 75 | ``` 76 | 77 | ## Development 78 | 79 | To see the effects of a change on a real Elasticsearch instance, build the package and install it like so: 80 | 81 | ```bash 82 | plugin="/Users/you/elasticsearch-/bin/plugin" 83 | name="srv-discovery" 84 | zip="file:///Users/you/elasticsearch-srv-discovery/build/distributions/elasticsearch-srv-discovery-.zip" 85 | 86 | gradle distZip || exit 1 87 | $plugin remove $name 88 | $plugin install $name --url $zip 89 | ``` 90 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | import org.apache.tools.ant.filters.*; 2 | 3 | group = 'org.elasticsearch' 4 | version = '1.5.1' 5 | 6 | apply plugin: 'java' 7 | apply plugin: 'java-library-distribution' 8 | 9 | configurations { 10 | provided 11 | } 12 | 13 | processResources { 14 | expand(project.properties) 15 | } 16 | 17 | repositories { 18 | mavenCentral() 19 | } 20 | 21 | def elasticsearch_version = "1.5.0" 22 | def lucene_version = "4.10.4" 23 | 24 | dependencies { 25 | compile "org.apache.lucene:lucene-test-framework:$lucene_version" 26 | compile "org.elasticsearch:elasticsearch:$elasticsearch_version" 27 | compile(group: 'org.elasticsearch', name: 'elasticsearch', version: elasticsearch_version, classifier: 'tests') 28 | compile 'dnsjava:dnsjava:2.1.7' 29 | compile 'org.hamcrest:hamcrest-all:1.3' 30 | compile 'junit:junit:4.11' 31 | compile 'com.carrotsearch.randomizedtesting:randomizedtesting-runner:2.1.10' 32 | } 33 | -------------------------------------------------------------------------------- /src/main/assemblies/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | plugin 4 | 5 | zip 6 | 7 | false 8 | 9 | 10 | / 11 | true 12 | true 13 | 14 | org.elasticsearch:elasticsearch 15 | 16 | 17 | 18 | / 19 | true 20 | true 21 | 22 | dnsjava:dnsjava 23 | 24 | 25 | 26 | ˜ -------------------------------------------------------------------------------- /src/main/java/org/elasticsearch/discovery/srv/SrvDiscovery.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 GitHub 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, including without limitation 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | * and/or sell copies of the Software, and to permit persons to whom the Software 9 | * is furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 16 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 20 | * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | package org.elasticsearch.discovery.srv; 24 | 25 | import org.elasticsearch.cluster.ClusterName; 26 | import org.elasticsearch.cluster.ClusterService; 27 | import org.elasticsearch.cluster.node.DiscoveryNodeService; 28 | import org.elasticsearch.cluster.settings.DynamicSettings; 29 | import org.elasticsearch.common.inject.Inject; 30 | import org.elasticsearch.common.settings.Settings; 31 | import org.elasticsearch.discovery.DiscoverySettings; 32 | import org.elasticsearch.discovery.zen.ZenDiscovery; 33 | import org.elasticsearch.discovery.zen.elect.ElectMasterService; 34 | import org.elasticsearch.discovery.zen.ping.ZenPingService; 35 | import org.elasticsearch.node.settings.NodeSettingsService; 36 | import org.elasticsearch.threadpool.ThreadPool; 37 | import org.elasticsearch.transport.TransportService; 38 | 39 | /** 40 | * 41 | */ 42 | public class SrvDiscovery extends ZenDiscovery { 43 | 44 | @Inject 45 | public SrvDiscovery(Settings settings, ClusterName clusterName, ThreadPool threadPool, TransportService transportService, 46 | ClusterService clusterService, NodeSettingsService nodeSettingsService, ZenPingService pingService, 47 | DiscoveryNodeService discoveryNodeService,DiscoverySettings discoverySettings, 48 | ElectMasterService electMasterService, DynamicSettings dynamicSettings) { 49 | super(settings, clusterName, threadPool, transportService, clusterService, nodeSettingsService, 50 | discoveryNodeService, pingService, electMasterService, discoverySettings, dynamicSettings); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/org/elasticsearch/discovery/srv/SrvDiscoveryModule.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 GitHub 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, including without limitation 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | * and/or sell copies of the Software, and to permit persons to whom the Software 9 | * is furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 16 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 20 | * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | package org.elasticsearch.discovery.srv; 24 | 25 | import org.elasticsearch.common.inject.Inject; 26 | import org.elasticsearch.common.settings.Settings; 27 | import org.elasticsearch.discovery.Discovery; 28 | import org.elasticsearch.discovery.zen.ZenDiscoveryModule; 29 | 30 | /** 31 | * 32 | */ 33 | public class SrvDiscoveryModule extends ZenDiscoveryModule { 34 | 35 | @Inject 36 | public SrvDiscoveryModule(Settings settings) { 37 | addUnicastHostProvider(SrvUnicastHostsProvider.class); 38 | } 39 | 40 | @Override 41 | protected void bindDiscovery() { 42 | bind(Discovery.class).to(SrvDiscovery.class).asEagerSingleton(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/org/elasticsearch/discovery/srv/SrvUnicastHostsProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 GitHub 3 | * Portions copyright (c) 2015 Crate.IO. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the "Software"), 7 | * to deal in the Software without restriction, including without limitation 8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | * and/or sell copies of the Software, and to permit persons to whom the Software 10 | * is furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 21 | * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | package org.elasticsearch.discovery.srv; 25 | 26 | import org.elasticsearch.Version; 27 | import org.elasticsearch.cluster.node.DiscoveryNode; 28 | import org.elasticsearch.common.Nullable; 29 | import org.elasticsearch.common.collect.Lists; 30 | import org.elasticsearch.common.component.AbstractComponent; 31 | import org.elasticsearch.common.inject.Inject; 32 | import org.elasticsearch.common.settings.Settings; 33 | import org.elasticsearch.common.transport.TransportAddress; 34 | import org.elasticsearch.discovery.zen.ping.unicast.UnicastHostsProvider; 35 | import org.elasticsearch.transport.TransportService; 36 | import org.xbill.DNS.*; 37 | 38 | import java.net.UnknownHostException; 39 | import java.util.ArrayList; 40 | import java.util.Arrays; 41 | import java.util.List; 42 | 43 | /** 44 | * 45 | */ 46 | public class SrvUnicastHostsProvider extends AbstractComponent implements UnicastHostsProvider { 47 | 48 | public static final String DISCOVERY_SRV_QUERY = "discovery.srv.query"; 49 | public static final String DISCOVERY_SRV_SERVERS = "discovery.srv.servers"; 50 | 51 | public static final String DISCOVERY_SRV_PROTOCOL = "discovery.srv.protocol"; 52 | 53 | private final TransportService transportService; 54 | 55 | private final Version version; 56 | 57 | private final String query; 58 | private final Resolver resolver; 59 | 60 | @Inject 61 | public SrvUnicastHostsProvider(Settings settings, TransportService transportService, Version version) { 62 | super(settings); 63 | this.transportService = transportService; 64 | this.version = version; 65 | 66 | this.query = settings.get(DISCOVERY_SRV_QUERY); 67 | logger.debug("Using query {}", this.query); 68 | this.resolver = buildResolver(settings); 69 | } 70 | 71 | @Nullable 72 | protected Resolver buildResolver(Settings settings) { 73 | String[] addresses = settings.getAsArray(DISCOVERY_SRV_SERVERS); 74 | logger.debug("Using servers {}", addresses); 75 | 76 | // Use tcp by default since it retrieves all records 77 | String protocol = settings.get(DISCOVERY_SRV_PROTOCOL, "tcp"); 78 | logger.debug("Using protocol {}", protocol); 79 | 80 | List resolvers = Lists.newArrayList(); 81 | 82 | for (String address : addresses) { 83 | String host = null; 84 | int port = -1; 85 | String[] parts = address.split(":"); 86 | if (parts.length > 0) { 87 | host = parts[0]; 88 | if (parts.length > 1) { 89 | try { 90 | port = Integer.valueOf(parts[1]); 91 | } catch (Exception e) { 92 | logger.warn("Resolver port '{}' is not an integer. Using default port 53", parts[1]); 93 | } 94 | } 95 | 96 | } 97 | 98 | try { 99 | Resolver resolver = new SimpleResolver(host); 100 | if (port > 0) { 101 | resolver.setPort(port); 102 | } 103 | resolvers.add(resolver); 104 | logger.debug("Added a resolver for host {} port {}", host, port); 105 | } catch (UnknownHostException e) { 106 | logger.warn("Could not create resolver for '{}'", address, e); 107 | } 108 | } 109 | 110 | Resolver parent_resolver = null; 111 | 112 | if (resolvers.size() > 0) { 113 | try { 114 | parent_resolver = new ExtendedResolver(resolvers.toArray(new Resolver[resolvers.size()])); 115 | 116 | if (protocol.equals("tcp")) { 117 | parent_resolver.setTCP(true); 118 | } 119 | 120 | logger.debug("Created an ExtendedResolver using {} resolvers and protocol {}", resolvers.size(), protocol); 121 | } catch (UnknownHostException e) { 122 | logger.warn("Could not create resolver. Using default resolver.", e); 123 | } 124 | } 125 | 126 | parent_resolver = parent_resolver == null ? Lookup.getDefaultResolver() : parent_resolver; 127 | 128 | if (protocol == "tcp") { 129 | parent_resolver.setTCP(true); 130 | } 131 | 132 | return parent_resolver; 133 | } 134 | 135 | public List buildDynamicNodes() { 136 | List discoNodes = Lists.newArrayList(); 137 | if (query == null) { 138 | logger.error("DNS query must not be null. Please set '{}'", DISCOVERY_SRV_QUERY); 139 | return discoNodes; 140 | } 141 | try { 142 | logger.trace("Building dynamic discovery nodes..."); 143 | discoNodes = lookupNodes(); 144 | if (discoNodes.size() == 0) { 145 | logger.debug("No nodes found"); 146 | } 147 | } catch (TextParseException e) { 148 | logger.error("Unable to parse DNS query '{}'", query); 149 | logger.error("DNS lookup exception:", e); 150 | } 151 | logger.debug("Using dynamic discovery nodes {}", discoNodes); 152 | return discoNodes; 153 | } 154 | 155 | protected List lookupRecords(String query, int type) throws TextParseException { 156 | Lookup lookup = new Lookup(query, type); 157 | if (this.resolver != null) { 158 | lookup.setResolver(this.resolver); 159 | } 160 | 161 | Record[] records = lookup.run(); 162 | return records == null ? new ArrayList() : Arrays.asList(records); 163 | } 164 | 165 | protected List lookupNodes() throws TextParseException { 166 | List discoNodes = Lists.newArrayList(); 167 | 168 | for (Record srvRecord : lookupRecords(query, Type.SRV)) { 169 | logger.trace("Found SRV record {}", srvRecord); 170 | for (Record aRecord : lookupRecords(((SRVRecord) srvRecord).getTarget().toString(), Type.A)) { 171 | logger.trace("Found A record {} for SRV record", aRecord, srvRecord); 172 | String address = ((ARecord) aRecord).getAddress().getHostAddress() + ":" + ((SRVRecord) srvRecord).getPort(); 173 | try { 174 | for (TransportAddress transportAddress : transportService.addressesFromString(address)) { 175 | logger.trace("adding {}, transport_address {}", address, transportAddress); 176 | discoNodes.add(new DiscoveryNode("#srv-" + address + "-" + transportAddress, transportAddress, version.minimumCompatibilityVersion())); 177 | } 178 | } catch (Exception e) { 179 | logger.warn("failed to add {}, address {}", e, address); 180 | } 181 | } 182 | } 183 | 184 | return discoNodes; 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /src/main/java/org/elasticsearch/discovery/srvtest/Constants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 GitHub 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, including without limitation 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | * and/or sell copies of the Software, and to permit persons to whom the Software 9 | * is furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 16 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 20 | * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | package org.elasticsearch.discovery.srvtest; 24 | 25 | public class Constants { 26 | public static final String TEST_QUERY = "test-tag.test-service.service.test."; 27 | public static final int NODE_0_TRANSPORT_TCP_PORT = 9300; 28 | public static final int NODE_1_TRANSPORT_TCP_PORT = 9301; 29 | public static final int NODE_2_TRANSPORT_TCP_PORT = 9302; 30 | public static final int NODE_3_TRANSPORT_TCP_PORT = 9303; 31 | public static final int NODE_4_TRANSPORT_TCP_PORT = 9304; 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/org/elasticsearch/discovery/srvtest/SrvtestDiscovery.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 GitHub 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, including without limitation 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | * and/or sell copies of the Software, and to permit persons to whom the Software 9 | * is furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 16 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 20 | * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | package org.elasticsearch.discovery.srvtest; 24 | 25 | import org.elasticsearch.cluster.ClusterName; 26 | import org.elasticsearch.cluster.ClusterService; 27 | import org.elasticsearch.cluster.node.DiscoveryNodeService; 28 | import org.elasticsearch.cluster.settings.DynamicSettings; 29 | import org.elasticsearch.common.inject.Inject; 30 | import org.elasticsearch.common.settings.Settings; 31 | import org.elasticsearch.discovery.DiscoverySettings; 32 | import org.elasticsearch.discovery.zen.ZenDiscovery; 33 | import org.elasticsearch.discovery.zen.elect.ElectMasterService; 34 | import org.elasticsearch.discovery.zen.ping.ZenPingService; 35 | import org.elasticsearch.node.settings.NodeSettingsService; 36 | import org.elasticsearch.threadpool.ThreadPool; 37 | import org.elasticsearch.transport.TransportService; 38 | 39 | public class SrvtestDiscovery extends ZenDiscovery { 40 | @Inject 41 | public SrvtestDiscovery(Settings settings, ClusterName clusterName, ThreadPool threadPool, TransportService transportService, 42 | ClusterService clusterService, NodeSettingsService nodeSettingsService, ZenPingService pingService, 43 | DiscoveryNodeService discoveryNodeService,DiscoverySettings discoverySettings, 44 | ElectMasterService electMasterService, DynamicSettings dynamicSettings) { 45 | super(settings, clusterName, threadPool, transportService, clusterService, nodeSettingsService, 46 | discoveryNodeService, pingService, electMasterService, discoverySettings, dynamicSettings); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/org/elasticsearch/discovery/srvtest/SrvtestDiscoveryModule.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 GitHub 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, including without limitation 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | * and/or sell copies of the Software, and to permit persons to whom the Software 9 | * is furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 16 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 20 | * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | package org.elasticsearch.discovery.srvtest; 24 | 25 | import org.elasticsearch.common.inject.Inject; 26 | import org.elasticsearch.common.settings.Settings; 27 | import org.elasticsearch.discovery.Discovery; 28 | import org.elasticsearch.discovery.zen.ZenDiscoveryModule; 29 | 30 | public class SrvtestDiscoveryModule extends ZenDiscoveryModule { 31 | @Inject 32 | public SrvtestDiscoveryModule(Settings settings) { 33 | addUnicastHostProvider(SrvtestUnicastHostsProvider.class); 34 | } 35 | 36 | @Override 37 | protected void bindDiscovery() { 38 | bind(Discovery.class).to(SrvtestDiscovery.class).asEagerSingleton(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/org/elasticsearch/discovery/srvtest/SrvtestUnicastHostsProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 GitHub 3 | * Portions copyright (c) 2015 Crate.IO. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the "Software"), 7 | * to deal in the Software without restriction, including without limitation 8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | * and/or sell copies of the Software, and to permit persons to whom the Software 10 | * is furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 21 | * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | package org.elasticsearch.discovery.srvtest; 25 | 26 | import org.elasticsearch.Version; 27 | import org.elasticsearch.common.inject.Inject; 28 | import org.elasticsearch.common.settings.Settings; 29 | import org.elasticsearch.discovery.srv.SrvUnicastHostsProvider; 30 | import org.elasticsearch.transport.TransportService; 31 | import org.xbill.DNS.*; 32 | 33 | import java.io.IOException; 34 | import java.net.InetAddress; 35 | import java.net.UnknownHostException; 36 | 37 | public class SrvtestUnicastHostsProvider extends SrvUnicastHostsProvider { 38 | @Inject 39 | public SrvtestUnicastHostsProvider(Settings settings, TransportService transportService, Version version) { 40 | super(settings, transportService, version); 41 | } 42 | 43 | @Override 44 | protected Resolver buildResolver(Settings settings) { 45 | try { 46 | return new SimpleResolver() { 47 | @Override 48 | public Message send(Message query) throws IOException { 49 | final String HOSTNAME = "localhost."; 50 | 51 | if (query.getQuestion().getName().toString().equals(Constants.TEST_QUERY)) { 52 | Record question = Record.newRecord(query.getQuestion().getName(), Type.SRV, DClass.IN); 53 | Message queryMessage = Message.newQuery(question); 54 | 55 | Message result = new Message(); 56 | result.setHeader(queryMessage.getHeader()); 57 | result.addRecord(question, Section.QUESTION); 58 | 59 | result.addRecord(new SRVRecord(query.getQuestion().getName(), DClass.IN, 1, 1, 1, Constants.NODE_0_TRANSPORT_TCP_PORT, Name.fromString(HOSTNAME)), Section.ANSWER); 60 | result.addRecord(new SRVRecord(query.getQuestion().getName(), DClass.IN, 1, 1, 1, Constants.NODE_1_TRANSPORT_TCP_PORT, Name.fromString(HOSTNAME)), Section.ANSWER); 61 | result.addRecord(new SRVRecord(query.getQuestion().getName(), DClass.IN, 1, 1, 1, Constants.NODE_2_TRANSPORT_TCP_PORT, Name.fromString(HOSTNAME)), Section.ANSWER); 62 | result.addRecord(new SRVRecord(query.getQuestion().getName(), DClass.IN, 1, 1, 1, Constants.NODE_3_TRANSPORT_TCP_PORT, Name.fromString(HOSTNAME)), Section.ANSWER); 63 | result.addRecord(new SRVRecord(query.getQuestion().getName(), DClass.IN, 1, 1, 1, Constants.NODE_4_TRANSPORT_TCP_PORT, Name.fromString(HOSTNAME)), Section.ANSWER); 64 | return result; 65 | } 66 | 67 | if (query.getQuestion().getName().toString().equals(HOSTNAME)) { 68 | Record question = Record.newRecord(query.getQuestion().getName(), Type.A, DClass.IN); 69 | Message queryMessage = Message.newQuery(question); 70 | 71 | Message result = new Message(); 72 | result.setHeader(queryMessage.getHeader()); 73 | result.addRecord(question, Section.QUESTION); 74 | 75 | result.addRecord(new ARecord(query.getQuestion().getName(), DClass.IN, 1, InetAddress.getLoopbackAddress()), Section.ANSWER); 76 | return result; 77 | } 78 | 79 | throw new IllegalArgumentException("Unknown test query: " + query.getQuestion().getName().toString()); 80 | } 81 | }; 82 | } catch (UnknownHostException e) { 83 | throw new RuntimeException(e); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/org/elasticsearch/plugin/discovery/SrvDiscoveryPlugin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 GitHub 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, including without limitation 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | * and/or sell copies of the Software, and to permit persons to whom the Software 9 | * is furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 16 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 20 | * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | package org.elasticsearch.plugin.discovery; 24 | 25 | import org.elasticsearch.common.settings.Settings; 26 | import org.elasticsearch.plugins.AbstractPlugin; 27 | 28 | public class SrvDiscoveryPlugin extends AbstractPlugin { 29 | 30 | private final Settings settings; 31 | 32 | public SrvDiscoveryPlugin(Settings settings) { 33 | this.settings = settings; 34 | } 35 | 36 | @Override 37 | public String name() { 38 | return "srv-discovery"; 39 | } 40 | 41 | @Override 42 | public String description() { 43 | return "SRV Discovery Plugin"; 44 | } 45 | 46 | 47 | } -------------------------------------------------------------------------------- /src/main/resources/es-plugin.properties: -------------------------------------------------------------------------------- 1 | plugin=org.elasticsearch.plugin.discovery.SrvDiscoveryPlugin 2 | version=${project.version} 3 | -------------------------------------------------------------------------------- /src/test/java/org/elasticsearch/discovery/srv/SrvDiscoveryIntegrationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 GitHub 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, including without limitation 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | * and/or sell copies of the Software, and to permit persons to whom the Software 9 | * is furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 16 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 20 | * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | package org.elasticsearch.discovery.srv; 24 | 25 | import org.elasticsearch.common.settings.ImmutableSettings; 26 | import org.elasticsearch.discovery.srvtest.Constants; 27 | import org.elasticsearch.test.ElasticsearchIntegrationTest; 28 | import org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope; 29 | import org.junit.Test; 30 | 31 | import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder; 32 | 33 | @ClusterScope(scope = ElasticsearchIntegrationTest.Scope.SUITE, numDataNodes = 0) 34 | public class SrvDiscoveryIntegrationTest extends ElasticsearchIntegrationTest { 35 | @Test 36 | public void testClusterSrvDiscoveryWith2Nodes() throws Exception { 37 | ImmutableSettings.Builder b = settingsBuilder() 38 | .put("node.mode", "network") 39 | .put("discovery.zen.ping.multicast.enabled", "false") 40 | .put("discovery.type", "srvtest") 41 | .put(SrvUnicastHostsProvider.DISCOVERY_SRV_QUERY, Constants.TEST_QUERY); 42 | 43 | assertEquals(cluster().size(), 0); 44 | 45 | internalCluster().startNode(b.put("transport.tcp.port", String.valueOf(Constants.NODE_0_TRANSPORT_TCP_PORT)).build()); 46 | internalCluster().startNode(b.put("transport.tcp.port", String.valueOf(Constants.NODE_1_TRANSPORT_TCP_PORT)).build()); 47 | 48 | assertEquals(cluster().size(), 2); 49 | } 50 | 51 | @Test 52 | public void testClusterSrvDiscoveryWith5Nodes() throws Exception { 53 | ImmutableSettings.Builder b = settingsBuilder() 54 | .put("node.mode", "network") 55 | .put("discovery.zen.ping.multicast.enabled", "false") 56 | .put("discovery.type", "srvtest") 57 | .put(SrvUnicastHostsProvider.DISCOVERY_SRV_QUERY, Constants.TEST_QUERY); 58 | 59 | assertEquals(cluster().size(), 0); 60 | 61 | internalCluster().startNode(b.put("transport.tcp.port", String.valueOf(Constants.NODE_0_TRANSPORT_TCP_PORT)).build()); 62 | internalCluster().startNode(b.put("transport.tcp.port", String.valueOf(Constants.NODE_1_TRANSPORT_TCP_PORT)).build()); 63 | internalCluster().startNode(b.put("transport.tcp.port", String.valueOf(Constants.NODE_2_TRANSPORT_TCP_PORT)).build()); 64 | internalCluster().startNode(b.put("transport.tcp.port", String.valueOf(Constants.NODE_3_TRANSPORT_TCP_PORT)).build()); 65 | internalCluster().startNode(b.put("transport.tcp.port", String.valueOf(Constants.NODE_4_TRANSPORT_TCP_PORT)).build()); 66 | 67 | assertEquals(cluster().size(), 5); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/test/log4j.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | --------------------------------------------------------------------------------