package net.floodlightcontroller.hand;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import net.floodlightcontroller.packet.IPv4;
import org.restlet.resource.Get;
import org.restlet.resource.Post;
import org.restlet.resource.Delete;
import org.restlet.resource.ServerResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonToken;
import org.codehaus.jackson.map.MappingJsonFactory;
public class HANDGangliaHostsResource extends ServerResource {
public static Logger logger = LoggerFactory.getLogger(HANDGangliaHostsResource.class);
@Get("json")
public Object handleRequest(){
IHANDService hand =
(IHANDService)getContext().getAttributes().
get(IHANDService.class.getCanonicalName());
String status = null;
if(hand.isHANDEnabled()){
return hand.getHosts();
}
else{
status = "Please enable Host Aware Networking Decisions";
return ("{\"status\" : \"" + status + "\"}");
}
}
/**
*
* @param hostJson
* @return
*/
@Post
public String addHost(String hostJson){
IHANDService hand =
(IHANDService)getContext().getAttributes().
get(IHANDService.class.getCanonicalName());
HANDGangliaHost host;
String status = null;
try{
host = jsonToGangliaHost(hostJson);
}
catch(IOException e){
logger.error("Error parsing Ganglia host to JSON: {}, Error: {}", hostJson, e);
e.printStackTrace();
return "{\"status\" : \"Error! Could not parse Ganglia host, see log for details.\"}";
}
if(hostExists(host, hand.getHosts())){
status = "Error!, This host already exists!";
logger.error(status);
}
else{
if(hand.isHANDEnabled()){
/**Required Field Checks**/
//hostname and ip is required. b/c Ganglia stores RRD's by them.
if(host.hostName == null || host.ipAddress == 0){
status = "{\"status\" : \"Must provide Hostname and IP Address.\"}";
}
else if(host.cluster == null){
logger.info("Fetching Cluster Information...");
if(existsInAnyCluster(host)){
//Send to HAND Module for addition.
hand.addGangliaHost(host);
status = "{\"status\" : \"Adding host to Host Aware Network\"}";
}else{
status = "{\"status\" : \"Host does not exist in any cluster\"}";
}
}
//else just add it, it has enough information
else{
/** Should add a check cluster method here?**/
hand.addGangliaHost(host);
status = "{\"status\" : \"Adding host to Host Aware Network\"}";
}
/**
* Cluster will be add by existsInAnyCluster() if host RRD is found.
*
* MAC,and First Hop Switch will be added later b/c
* Floodlight will already has this info if not provided.
*/
}
}
return "{\"status\" : "+ status +"}";
}
/**
*
* @param hostJson
* @return
*/
@Delete
public String deleteHost(String hostJson){
//TODO
/**
*
* !!!!!!!!!!!!!!!!!!!!
*
*
*/
return null;
}
private static HANDGangliaHost jsonToGangliaHost(String hostJson) throws IOException{
HANDGangliaHost host = new HANDGangliaHost();
MappingJsonFactory jsonFactory = new MappingJsonFactory();
JsonParser parser;
try{
parser = jsonFactory.createJsonParser(hostJson);
}catch(JsonParseException e){
throw new IOException (e);
}
JsonToken token = parser.getCurrentToken();
if(token != JsonToken.START_OBJECT){
parser.nextToken();
if(parser.getCurrentToken() != JsonToken.START_OBJECT){
logger.error("did not recieve json start token, current token is: {}"
+ parser.getCurrentToken());
}
}
//Start parsing
while(parser.nextToken() != JsonToken.END_OBJECT){
if(parser.getCurrentToken() != JsonToken.FIELD_NAME){
throw new IOException("FIELD_NAME expected");
}
try{
String name = parser.getCurrentName();
parser.nextToken();
//current text in parser
String jsonText = parser.getText();
logger.info("JSON Parser text is: {}", jsonText); //DEBUG
if(jsonText.equals("")){
//ignore empty string, return to loop
continue;
}
else if(name == "host_name"){
host.hostName = jsonText;
}
else if(name == "ip_address"){
host.ipAddress = IPv4.toIPv4Address(jsonText);
}
else if(name == "domain"){
host.domain = jsonText;
}
else if(name == "mac_address"){
host.macAddress = Long.parseLong(jsonText);
}
else if(name == "cluster"){
host.cluster = jsonText;
}
//adds a list of SwitchDPIDs
//ex: {"first_hops":"123456789,987654321"}
else if(name == "first_hops"){
if(jsonText.contains(",")){
String[] hops = jsonText.split(",");
for(String s : hops){
host.firstHops.add(Long.valueOf(s));
}
}else{
//only one first hop
//ex: {"first_hops":"123456789"}
host.firstHops.add(Long.valueOf(jsonText));
}
}
}catch(JsonParseException e){
logger.debug("Error getting current FIELD_NAME {}", e);
}catch(IOException e){
logger.debug("Error procession Json {}", e);
}
}
//Return the HANDGangliaHost Object to the GangliaHostResource
return host;
}
/**
*
* @param host
* @param hostList
* @return
*/
public static boolean hostExists(HANDGangliaHost host,
ArrayList<HANDGangliaHost> hostList){
Iterator<HANDGangliaHost> hostIter = hostList.iterator();
while(hostIter.hasNext()){
HANDGangliaHost h = hostIter.next();
if(host.isSameAs(h) || host.macAddress == h.macAddress){
return true;
}
}
return false;
}
/**
* Checks to make sure a cluster exists for this Host
* By searching the RRD directory given in properties
* and making sure the host RRD exists within a cluster directory.
* @param host
* @return
*/
public static boolean existsInAnyCluster(HANDGangliaHost host){
//if found
boolean found = false;
//Get the consumer to get basepath.
MetricConsumer aConsumer = new MetricConsumer();
String dir = aConsumer.metricPath;
String fqdn;
if(host.domain == "" && !(host.hostName.contains("."))){
logger.info("hostname seems to not have a domain, adding .local");
host.domain = ".local";
fqdn = host.hostName+host.domain;
}else{
logger.info("hostname seems to contain it's domain name");
fqdn = host.hostName;
}
File containingPath = new File(dir);
logger.info("Searching for clusters in: {}", containingPath.getPath()); //debug
for( File child : containingPath.listFiles()){
//check if directory, clusters are listed as directories in Unix File Systems
if(child.isDirectory() && !(child.toString().contains("unspecified"))
&& !(child.toString().contains("__SummaryInfo__")) ){
logger.info("Checking Cluster: {}", child.toString()); //debug
String[] strDirs = child.toString().split("/");
String curDir = strDirs[strDirs.length-1];
for(File rrd : child.listFiles()){
String[] strRRDs = rrd.toString().split("/");
String compareRRD = strRRDs[strRRDs.length-1];
logger.debug("Comparing : "+fqdn+" or "+IPv4.fromIPv4Address(
host.ipAddress).toLowerCase()+ " to {}", compareRRD ); //DEBUG
if(compareRRD.contains(fqdn.toLowerCase())){
found = true;
//this is the current directory
//being searched.
host.cluster = curDir;
break;
}
else {
new String();
if(compareRRD.contains(IPv4.fromIPv4Address(
host.ipAddress).toLowerCase())){
found = true;
//We only want what ganglia can see.
host.hostName = "";
//set the host's cluster if found
//this is the current directory
//being searched.
host.cluster = curDir;
break;
}
}
}
}
}
return found;
}
}