/*
* Copyright (c) 2008-2015, Hazelcast, Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hazelcast.examples.spi.discovery;
import com.hazelcast.config.NetworkConfig;
import com.hazelcast.logging.ILogger;
import com.hazelcast.nio.Address;
import com.hazelcast.spi.discovery.AbstractDiscoveryStrategy;
import com.hazelcast.spi.discovery.DiscoveryNode;
import com.hazelcast.spi.discovery.SimpleDiscoveryNode;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* THIS CODE IS NOT PRODUCTION READY!
*/
public class HostsDiscoveryStrategy extends AbstractDiscoveryStrategy {
private static final String HOSTS_NIX = "/etc/hosts";
private static final String HOSTS_WINDOWS = "%SystemRoot%\\system32\\drivers\\etc\\hosts";
private final String siteDomain;
HostsDiscoveryStrategy(ILogger logger, Map<String, Comparable> properties) {
super(logger, properties);
// make it possible to override the value from the configuration on
// the system's environment or JVM properties -Ddiscovery.hosts.site-domain=some.domain
this.siteDomain = getOrNull("discovery.hosts", HostsDiscoveryConfiguration.DOMAIN);
}
@Override
public Iterable<DiscoveryNode> discoverNodes() {
List<String> assignments = filterHosts();
return mapToDiscoveryNodes(assignments);
}
private List<String> filterHosts() {
String os = System.getProperty("os.name");
String hostsPath;
if (os.contains("Windows")) {
hostsPath = HOSTS_WINDOWS;
} else {
hostsPath = HOSTS_NIX;
}
File hosts = new File(hostsPath);
// read all lines
List<String> lines = readLines(hosts);
List<String> assignments = new ArrayList<String>();
for (String line : lines) {
// example:
// 192.168.0.1 host1.cluster.local
if (matchesDomain(line)) {
assignments.add(line);
}
}
return assignments;
}
private Iterable<DiscoveryNode> mapToDiscoveryNodes(List<String> assignments) {
Collection<DiscoveryNode> discoveredNodes = new ArrayList<DiscoveryNode>();
for (String assignment : assignments) {
String address = sliceAddress(assignment);
String hostname = sliceHostname(assignment);
Map<String, Object> attributes = Collections.<String, Object>singletonMap("hostname", hostname);
InetAddress inetAddress = mapToInetAddress(address);
Address addr = new Address(inetAddress, NetworkConfig.DEFAULT_PORT);
discoveredNodes.add(new SimpleDiscoveryNode(addr, attributes));
}
return discoveredNodes;
}
private List<String> readLines(File hosts) {
try {
List<String> lines = new ArrayList<String>();
BufferedReader reader = new BufferedReader(new FileReader(hosts));
String line;
while ((line = reader.readLine()) != null) {
line = line.trim();
if (!line.startsWith("#")) {
lines.add(line.trim());
}
}
return lines;
} catch (IOException e) {
throw new RuntimeException("Could not read hosts file", e);
}
}
private boolean matchesDomain(String line) {
if (line.isEmpty()) {
return false;
}
String hostname = sliceHostname(line);
return hostname.endsWith("." + siteDomain);
}
private String sliceAddress(String assignment) {
String[] tokens = assignment.split("\\p{javaSpaceChar}+");
if (tokens.length < 1) {
throw new RuntimeException("Could not find ip address in " + assignment);
}
return tokens[0];
}
private static String sliceHostname(String assignment) {
String[] tokens = assignment.split("(\\p{javaSpaceChar}+|\t+)+");
if (tokens.length < 2) {
throw new RuntimeException("Could not find hostname in " + assignment);
}
return tokens[1];
}
private InetAddress mapToInetAddress(String address) {
try {
return InetAddress.getByName(address);
} catch (UnknownHostException e) {
throw new RuntimeException("Could not resolve ip address", e);
}
}
}