package com.github.martinprillard.shavadoop.network;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import com.github.martinprillard.shavadoop.util.Constant;
import com.github.martinprillard.shavadoop.util.Util;
import com.jcabi.ssh.SSH;
import com.jcabi.ssh.Shell;
import com.github.martinprillard.shavadoop.util.PropReader;
/**
*
* @author martin prillard
*
*/
public class SSHManager {
private List<String> hostsNetwork;
private int shellPort = 0;
private String fileIpAdress = null;
private String dsaFile = null;
private String dsaKey = null;
private PropReader prop = new PropReader();
private String hostFull;
private String hostFullMaster;
private String username = System.getProperty("user.name");
private String homeDirectory = System.getProperty("user.home");
private String ipAdress;
public SSHManager(String _hostFullMaster) {
hostFullMaster = _hostFullMaster;
}
/**
* Initialize the SSH manager
*/
public void initialize() {
if (Constant.MODE_DEBUG)
System.out.println("Initialize SSH Manager :");
shellPort = Integer.parseInt(prop.getPropValues(PropReader.PORT_SHELL));
dsaFile = prop.getPropValues(PropReader.FILE_DSA);
if (dsaFile == null || dsaFile.isEmpty() || dsaFile.trim().equalsIgnoreCase("")) {
dsaFile = homeDirectory + Constant.PATH_DSA_DEFAULT_FILE;
}
fileIpAdress = Constant.PATH_NETWORK_IP_FILE;
try {
hostFull = InetAddress.getLocalHost().getCanonicalHostName();
ipAdress = InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
e.printStackTrace();
}
// get dsa key
dsaKey = getDsaKeyContent(dsaFile);
}
/**
* Return x hosts alive
*
* @param nbWorker
* @param random
* @param forceInitialize
* @return list host's cores alive
*/
public List<String> getHostAliveCores(int nbWorker, boolean random, boolean forceInitialize) {
if (hostsNetwork == null) {
// get the list of hosts of the network
hostsNetwork = getHostFromFile(random);
}
if (Constant.MODE_DEBUG)
System.out.println("Search " + nbWorker + " worker(s) alive...");
List<String> hostAlive = new ArrayList<String>();
Set<String> initializedHost = new HashSet<String>();
ExecutorService es = Executors.newCachedThreadPool();
// if need more worker, use the distant computer
for (String host : hostsNetwork) {
if (hostAlive.size() < nbWorker) {
if (isMaster(host)) {
// add to our list of cores alive
hostAlive.add(host);
if (!initializedHost.contains(host)) {
initializedHost.add(host);
es.execute(new LaunchInitializeHost(this, es, host, true, forceInitialize));
}
} else if (isAlive(host)) {
for (int i = 0; i < getCoresNumber(host); i++) {
if (hostAlive.size() < nbWorker) {
// add to our list of cores alive
hostAlive.add(host);
if (!initializedHost.contains(host)) {
initializedHost.add(host);
es.execute(new LaunchInitializeHost(this, es, host, false, forceInitialize));
}
} else {
break;
}
}
}
} else {
break;
}
}
es.shutdown();
try {
es.awaitTermination(Constant.THREAD_MAX_LIFETIME, TimeUnit.MINUTES);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (Constant.MODE_DEBUG)
System.out.println(hostAlive.size() + " worker(s) alive found !");
return hostAlive;
}
/**
* Test if a host is alive
*
* @param host
* @return true if it's alive
*/
public boolean isAlive(String host) {
boolean alive = false;
// test if this host is alive
try {
String cmd = "echo " + host;
Shell shell = new SSH(host, shellPort, Constant.USERNAME, dsaKey);
new Shell.Plain(shell).exec(cmd);
alive = true;
} catch (Exception e) {
} // fail to connect to the host
return alive;
}
/**
* Return the cores number from the distant computer
*
* @param host
* @return cores
*/
public int getCoresNumber(String host) {
int cores = 0;
// test if this host is alive
try {
// get the number of cores
String cmd = "grep -c ^processor /proc/cpuinfo";
Shell shell = new SSH(host, shellPort, Constant.USERNAME, dsaKey);
String stdout = new Shell.Plain(shell).exec(cmd);
cores = Integer.parseInt(stdout.trim());
} catch (Exception e) {
e.printStackTrace();
}
return cores;
}
/**
* Return list of hostname from a file
*
* @param random
* @return list hosts from the file
*/
public List<String> getHostFromFile(boolean random) {
List<String> hostnameMappers = new ArrayList<String>();
// check first for this computer : the master is the worker
int cores = Runtime.getRuntime().availableProcessors() - 1;
for (int i = 0; i < cores; i++) {
hostnameMappers.add(hostFull);
}
try {
FileReader fic = new FileReader(fileIpAdress);
BufferedReader read = new BufferedReader(fic);
String line = null;
while ((line = read.readLine()) != null) {
hostnameMappers.add(line);
}
fic.close();
read.close();
} catch (IOException e) {
e.printStackTrace();
}
if (random) {
Collections.shuffle(hostnameMappers);
}
return hostnameMappers;
}
/**
* Return the dsa key
*
* @param dsaFile
* @return dsa key
*/
public String getDsaKeyContent(String dsaFile) {
String dsaKeyContent = null;
try {
InputStream ips = new FileInputStream(dsaFile);
InputStreamReader ipsr = new InputStreamReader(ips);
BufferedReader br = new BufferedReader(ipsr);
String line;
while ((line = br.readLine()) != null) {
dsaKeyContent += line + "\n";
}
br.close();
if (Constant.MODE_DEBUG)
System.out.println("Dsa key found");
} catch (IOException e) {
System.out.println("No dsa file");
}
return dsaKeyContent;
}
/**
* Get the network's ip adress
*
* @param regex
*/
public void generateNetworkIpAdress(String regex) {
String cmdLine = "nmap -sn " + ipAdress + "/24 | awk \'{print $5}\' | grep -o " + regex;
try {
String line;
// run a java app in a separate system process
String[] cmd = { "/bin/sh", "-c", cmdLine };
Process p = Runtime.getRuntime().exec(cmd);
p.waitFor();
List<String> listIpAdress = new ArrayList<String>();
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((line = in.readLine()) != null) {
listIpAdress.add(line);
}
in.close();
if (Constant.MODE_DEBUG)
System.out.println("On local : " + cmdLine);
Util.writeFile(Constant.PATH_NETWORK_IP_DEFAULT_FILE, listIpAdress);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Return true if the worker is the master
*
* @param worker
* @return true if it's the master
*/
public boolean isMaster(String worker) {
boolean master = false;
if (worker.equalsIgnoreCase(hostFullMaster)) {
// the worker is the master
master = true;
}
return master;
}
/**
* Return true if the worker is local
*
* @param worker
* @return true if it's local
*/
public boolean isLocal(String worker) {
boolean local = false;
if (worker.equalsIgnoreCase(hostFull)) {
local = true;
}
return local;
}
public String getDsaKey() {
return dsaKey;
}
public String getHostFull() {
return hostFull;
}
public String getHostFullMaster() {
return hostFullMaster;
}
public int getShellPort() {
return shellPort;
}
public String getUsername() {
return username;
}
public void setHostFullMaster(String hostFullMaster) {
this.hostFullMaster = hostFullMaster;
}
}