/*
* Claudia Project
* http://claudia.morfeo-project.org
*
* (C) Copyright 2010 Telefonica Investigacion y Desarrollo
* S.A.Unipersonal (Telefonica I+D)
*
* See CREDITS file for info about members and contributors.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the Affero GNU General Public License (AGPL) as
* published by the Free Software Foundation; either version 3 of the License,
* or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the Affero GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* If you want to use this software an plan to distribute a
* proprietary application in any way, and you are not licensing and
* distributing your source code under AGPL, you probably need to
* purchase a commercial license of the product. Please contact
* claudia-support@lists.morfeo-project.org for more information.
*/
package com.telefonica.claudia.slm.lifecyclemanager;
import java.io.BufferedInputStream;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.Serializable;
import java.net.URL;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import javax.jms.JMSException;
import javax.naming.NamingException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
import org.json.JSONException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import com.telefonica.claudia.slm.common.DbManager;
import com.telefonica.claudia.slm.common.SMConfiguration;
import com.telefonica.claudia.slm.deployment.Customer;
import com.telefonica.claudia.slm.deployment.ProbeKPI;
import com.telefonica.claudia.slm.deployment.ServiceApplication;
import com.telefonica.claudia.slm.deployment.VEE;
import com.telefonica.claudia.slm.deployment.ServiceKPI;
import com.telefonica.claudia.slm.deployment.VEEReplica;
import com.telefonica.claudia.slm.deployment.hwItems.CPU;
import com.telefonica.claudia.slm.deployment.hwItems.Disk;
import com.telefonica.claudia.slm.deployment.hwItems.Memory;
import com.telefonica.claudia.slm.deployment.hwItems.NIC;
import com.telefonica.claudia.slm.eventsBus.BusListener;
import com.telefonica.claudia.slm.eventsBus.BusMediator;
import com.telefonica.claudia.slm.eventsBus.events.AdministrativeEvent;
import com.telefonica.claudia.slm.eventsBus.events.AgentMeasureEvent;
import com.telefonica.claudia.slm.eventsBus.events.Event;
import com.telefonica.claudia.slm.eventsBus.events.ProbeMeasureEvent;
import com.telefonica.claudia.slm.eventsBus.events.SMControlEvent;
import com.telefonica.claudia.slm.eventsBus.events.SMIChannelEvent;
import com.telefonica.claudia.slm.eventsBus.events.VeeHwMeasureEvent;
import com.telefonica.claudia.slm.eventsBus.events.Event.EventType;
import com.telefonica.claudia.slm.eventsBus.events.SMIChannelEvent.SMIAction;
import com.telefonica.claudia.slm.monitoring.ContextualizationListener;
import com.telefonica.claudia.slm.monitoring.MonitoringRestBusConnector;
import com.telefonica.claudia.slm.monitoring.WasupClient;
import com.telefonica.claudia.slm.monitoring.WasupHierarchy;
import com.telefonica.claudia.slm.naming.DirectoryEntry;
import com.telefonica.claudia.slm.naming.FQN;
import com.telefonica.claudia.slm.naming.ReservoirDirectory;
import com.telefonica.claudia.slm.rulesEngine.RulesEngine;
import com.telefonica.claudia.smi.DataTypesUtils;
import com.telefonica.claudia.smi.URICreation;
/**
* This class is the core of the SM, it manages the lifecycle of the finite
* state machine representing a single/or a set of services This element is
* connected to: - the SP through some parts of the SMI - SM components invoking
* controller methods - the FSMs themselves
*/
public class LifecycleController extends UnicastRemoteObject implements SMI,
Serializable, BusListener {
private static Logger logger = Logger.getLogger(LifecycleController.class);
private static Logger monitoringLog = Logger.getLogger("Monitoring");
static {
Logger.getLogger("com.telefonica.claudia.slm.lifecyclemanager")
.setLevel(Level.INFO);
Logger.getLogger("com.telefonica.claudia.slm.lifecyclemanager")
.addAppender(
new ConsoleAppender(new PatternLayout(
"%-5p [%t] %c{2}: %m%n"), "System.out"));
}
private static final long serialVersionUID = 1L;
private static final String manifestRepository = "./repository/manifestFiles";
private static final String manifestBuffer = "./repository/manifestBuffer";
private BusMediator busMediator = new BusMediator();
/**
* Reference to the monitorization hierarchy.
*/
private WasupHierarchy wasupClient;
/**
* Collection of network ranges available for making subnets.
*/
private List<NetworkRange> networkRanges = new ArrayList<NetworkRange>();
// event Buffer
private ArrayBlockingQueue<SMControlEvent> eventBuffer;
/**
* Map containing the buffer vectors for each FSM. The key is the service
* application FQN.
*/
private HashMap<String, ArrayBlockingQueue<SMControlEvent>> bufferVector;
private HashMap<FQN, RulesEngine> ruleEngineVector;
private HashMap<String, FSM> fsmVector;
// map service FQN to the corresponding LCC
private static HashMap<FQN, String> service2Controller = new HashMap<FQN, String>();
private static int count = 0;
private static int deploymentNum = 0;
// Monitoring endPoint
private String endPoint;
private enum LccStates {
INIT, RUNNING, FINISHING
};
List<Customer> customers = null;
/**
* Time the SLM will wait for the FSM to undeploy and finish, until killing
* it explicitly.
*/
private static final long FSM_FINISH_TIMEOUT = 8 * 60 * 1000;
private LccStates state = LccStates.INIT;
public LifecycleController() throws RemoteException, JMSException,
NamingException {
this.customers = new ArrayList<Customer>();
bufferVector = new HashMap<String, ArrayBlockingQueue<SMControlEvent>>();
ruleEngineVector = new HashMap<FQN, RulesEngine>();
fsmVector = new HashMap<String, FSM>();
MonitoringRestBusConnector restBusConnector = MonitoringRestBusConnector
.getInstance();
restBusConnector.start();
ContextualizationListener contextListener = ContextualizationListener.getInstance();
contextListener.start ();
// Connecting to JMS bus
try {
busMediator.openJMSSession();
} catch (NamingException ex) {
logger.error(
"Could not connect LifecycleController to JMS bus, NamingException caught: "
+ ex.getMessage(), ex);
return;
} catch (JMSException ex) {
logger.error(
"Could not connect LifecycleController to JMS bus, JMSException caught: "
+ ex.getMessage(), ex);
return;
}
// In order to use the WASUP, is it neccesary to create its element
// types.
// First off all, we should log in.
if (SMConfiguration.getInstance().isWasupActive()) {
try {
WasupClient.getWasupClient().login(
"http://"
+ SMConfiguration.getInstance().getWASUPHost()
+ ":"
+ SMConfiguration.getInstance().getWASUPPort()
+ SMConfiguration.getInstance().getWASUPPath(),
SMConfiguration.getInstance().getWASUPLogin(),
SMConfiguration.getInstance().getWASUPPassword());
WasupHierarchy.setParameters(SMConfiguration.getInstance()
.getCustomerType(), SMConfiguration.getInstance()
.getServiceType(), SMConfiguration.getInstance()
.getVeeType(), SMConfiguration.getInstance()
.getVeeReplicaType(), SMConfiguration.getInstance()
.getNetworkType(), SMConfiguration.getInstance()
.getHwType());
WasupHierarchy.loadWasupTypes();
wasupClient = WasupHierarchy.getWasupHierarchy();
} catch (IOException e) {
monitoringLog.error("Could not create WASUP element types: "
+ e.getMessage(), e);
} catch (JSONException e) {
monitoringLog.error("Error parsing the WASUP response: "
+ e.getMessage(), e);
} catch (Throwable e) {
monitoringLog.error("Unknow error connecting to WASUP: "
+ e.getMessage(), e);
}
}
// Registering for JMS events
busMediator.cleanQueues();
try {
busMediator.registerEventsReceiver(this,
EventType.AGENT_MEASUREMENT);
busMediator.registerEventsReceiver(this,
EventType.PROBE_MEASUREMENT);
busMediator.registerEventsReceiver(this,
EventType.VEE_HW_MEASUREMENT);
busMediator.registerEventsReceiver(this,
EventType.SMI_CHANNEL_EVENT);
busMediator.registerEventsReceiver(this,
EventType.ADMINISTRATIVE_EVENT);
busMediator.registerEventsReceiver(this, EventType.FSM_BUS_EVENT);
busMediator
.registerEventsReceiver(this, EventType.SM_CONTROL_EVENT);
} catch (JMSException ex) {
monitoringLog.error(
"Could not register for events to JMS bus, JMSException caught: "
+ ex.getMessage(), ex);
return;
}
loadSavedData();
loadNetworkRanges();
state = LccStates.RUNNING;
}
private void loadSavedData() {
List<ServiceApplication> services = DbManager.getDbManager().getList(
ServiceApplication.class);
for (ServiceApplication sap : services) {
logger.info("Restoring service " + sap.getSerAppName());
FSM fsm = new FSM(this, endPoint);
RulesEngine rle = new RulesEngine(this);
// "load" the rule engine into the FSM
fsm.loadRuleEngine(rle);
fsm.loadService(sap);
fsm.start();
ruleEngineVector.put(fsm.getServiceFQN(), rle);
service2Controller
.put(fsm.getServiceFQN(), String.valueOf(count++));
}
networkRanges = DbManager.getDbManager().getList(NetworkRange.class);
}
/**
* Read the network ranges definition from the Service Manager configuration
* and load them into the networkRanges array.
*
* The NetworkRanges property is composed of a list of network properties
* defined this way:
*
* [ IP:10.95.240.0, Netmask:255.255.240.0, Gateway:10.95.240.1,
* DNS:10.95.240.1 ]
*
*/
private void loadNetworkRanges() {
String[] networkAddresses = SMConfiguration.getInstance()
.getNetworkRanges();
for (String range : networkAddresses) {
loadNetworkAddress(range);
}
}
private void loadNetworkAddress(String range) {
if (!range
.replaceAll("\n| ", "")
.trim()
.matches(
"\\[((Network:\\d+\\.\\d+\\.\\d+.\\d+);?|"
+ "(IP:(\\d+\\.\\d+\\.\\d+.\\d+/?)+);?|"
+ "(Netmask:\\d+\\.\\d+\\.\\d+.\\d+);?|"
+ "(Gateway:\\d+\\.\\d+\\.\\d+.\\d+);?|"
+ "(DNS:\\d+\\.\\d+\\.\\d+.\\d+);?|(Public:(yes|no));?)+\\]")) {
logger
.warn("Wrong network address format. Expected: [IP:ip_value,Netmask:nmask_value,Gateway:gw_value,DNS:dns_value]");
return;
}
try {
int IPPos = range.indexOf("IP:");
String ip;
if (IPPos > 0) {
ip = range.substring(IPPos + 3, range.indexOf(";", IPPos))
.trim();
} else {
logger
.error("There must be one IP Address per network description.");
return;
}
int MaskPos = range.indexOf("Netmask:");
String mask;
if (MaskPos > 0)
mask = range
.substring(MaskPos + 8, range.indexOf(";", MaskPos))
.trim();
else
throw new IllegalArgumentException(
"Ranges must contain a Mask.");
NetworkRange nr;
if (ip.contains("/")) {
logger
.info("Creating a network leaser for IP addresses: "
+ ip);
int networkPos = range.indexOf("Network:");
String network;
if (networkPos > 0) {
network = range.substring(networkPos + 8,
range.indexOf(";", networkPos)).trim();
} else {
logger
.error("There must be one IP Address per network description.");
return;
}
NetworkLeaser nl = new NetworkLeaser();
nl.setIP(network);
nl.setMask(mask);
String[] ips = ip.split("/");
for (String ipLease : ips)
nl.addIPToPool(ipLease);
nr = nl;
} else {
logger.info("Creating network range for network address: " + ip
+ " with mask " + mask);
nr = new NetworkRange();
nr.setIP(ip);
nr.setMask(mask);
}
int GWPos = range.indexOf("Gateway:");
if (GWPos > 0)
nr.setGateway(range.substring(GWPos + 8,
range.indexOf(";", GWPos)).trim());
int DNSPos = range.indexOf("DNS:");
if (DNSPos > 0)
nr.setDNS(range.substring(DNSPos + 4,
range.indexOf(";", DNSPos)).trim());
int PublicPos = range.indexOf("Public:");
if (PublicPos > 0) {
if (range.substring(PublicPos + 7,
range.indexOf(";", PublicPos)).trim().equals("yes"))
nr.setPublic(true);
else
nr.setPublic(false);
}
if (!networkRangeExists(nr)) {
networkRanges.add(nr);
DbManager.getDbManager().save(nr);
} else
logger.info("Network range already loaded from DB: " + ip);
} catch (IllegalArgumentException iae) {
logger.warn("Wrong network address format: " + iae.getMessage());
return;
} catch (Throwable t) {
logger
.warn("Exception parsing network properties, check your syntax: "
+ t.getMessage());
return;
}
}
public boolean networkRangeExists(NetworkRange candidate) {
for (NetworkRange nr : networkRanges)
if (nr.getIP().equals(candidate.getIP()))
return true;
return false;
}
public int getController(FQN remoteFqn) {
Integer enter = Integer.parseInt((String) service2Controller
.get(remoteFqn));
return enter.intValue();
}
/**
* notify interested parties that the machine is up and running
*
* @param machine
* @returnint representing the current machine state 0 = is not running; 1 =
* is running
*/
protected int notifyRunning(FQN machine) {
// let the user know about the actual state of the machine
// BY UPDATING ANY FIELD IN THE DEPLOYMENT MODEL???
FSM checkFsm = (FSM) fsmVector.get(machine.toString());
if (checkFsm.getCurrentState() == FSM.RUNNING)
return 1;
else
return 0;
}
/**
* the controller keeps a list of the FQNs of the FSM services it controls
* the method is invoked by the FSM itself whenever it has been successfully
* created
*/
public void registerFSM(FQN serviceID, FSM finiteStateMachine) {
// add a new buffer for this service
eventBuffer = new ArrayBlockingQueue<SMControlEvent>(1000);
// add the buffer to the buffer pool
bufferVector.put(serviceID.toString(), eventBuffer);
fsmVector.put(serviceID.toString(), finiteStateMachine);
}
/**
* the controller deregisters a FSM whenever the user prompts to do it so or
* the FSM finishes its lifetime
*/
public void deregisterFSM(FQN serviceID) {
if (!bufferVector.isEmpty()) {
bufferVector.remove(serviceID.toString());
fsmVector.remove(serviceID.toString());
}
}
/**
* method to receive the incoming Events from other parts of the SM
*
* @param SM
* Control Event
*/
public void putEvent(SMControlEvent controlEvent) {
logger.info("\n\n* Sending Control Event to FSM: "
+ controlEvent.getServiceFQN().toString());
// check whether this controller is monitoring that service
if (bufferVector.containsKey(controlEvent.getServiceFQN().toString())) {
try {
// get the buffer for this Element
ArrayBlockingQueue<SMControlEvent> buffer = bufferVector
.get(controlEvent.getServiceFQN().toString());
// add event at the end of the queue and wait for space to be
// made
buffer.put(controlEvent);
// buffer.notify();
} catch (InterruptedException ex) {
logger
.error("The event buffer has been interrupted putting an event on the queue: "
+ ex.getMessage());
}
} else {
logger.error(controlEvent.getServiceFQN().toString()
+ " not in the current list of keys");
}
}
/**
* Method to be invoked by the FSM to check whether there has been any new
* event
*/
public SMControlEvent deliver(FQN serviceID) {
ArrayBlockingQueue<SMControlEvent> buffer = bufferVector.get(serviceID
.toString());
return buffer.poll();
}
/**
* Checks whether the provided serviceName is unique or it has been already
* deployed for the same customer. If there is a service with the same name
* and customer, it creates a sufix for the service name, so to make it
* unique.
*
* @param serviceName
* Candidate service name.
*
* @return A unique service name based upon the candidate.
*
*/
private String checkServiceName(String customerName, String serviceName) {
int i = 0;
String sufix = "";
String actualName = serviceName;
for (FQN fsmFQN : service2Controller.keySet()) {
ServiceApplication fsm = (ServiceApplication) ReservoirDirectory
.getInstance().getObject(fsmFQN);
if (fsm != null
&& fsm.getCustomer().getCustomerName().equals(customerName)
&& fsm.getSerAppName().equals(actualName + sufix)) {
i++;
sufix = String.valueOf(i);
}
}
return actualName + sufix;
}
/**
* Method invoked by the SP to command the deployment of a new service
*
* @param manifest
*/
@SuppressWarnings("deprecation")
public FQN deploy(URL manifest) {// throws RemoteException {
logger.info("Getting manifest file from URL " + manifest
+ " and copying it to local file " + manifestRepository
+ manifest.getFile());
String s;
InputStream is;
DataInputStream dis;
PrintWriter out;
try {
// download the URL and store the file in a local repository
is = manifest.openStream();
dis = new DataInputStream(new BufferedInputStream(is));
out = new PrintWriter(new FileWriter(manifestRepository
+ manifest.getFile()));
while ((s = dis.readLine()) != null) {
out.write(s + "\n");
}
is.close();
out.close();
} catch (IOException ex) {
logger.error("Could not copy remote file " + manifest + " to "
+ manifestRepository + manifest.getFile(), ex);
return null;
}
return deploy(new File(manifestRepository + manifest.getFile()),
"UNKNOWNCOSTUMER", "ANONYMOUSSERVICE");
}
/**
* Deploys the Service application defined in the manifest passed as a
* parameter.
*
*
* @param manifest
* File object representing the xml manifes file containing the
* description of the service.
*
* @param customer
* String identifier of the custumer who deploys the server.
*
* @return
*/
public FQN deploy(File manifest, String customerFqn, String serviceName) {
logger.info("Deploying manifest file " + manifest.getAbsolutePath());
// start the FSM
FSM fsm = new FSM(this, endPoint);
fsm.loadManifest(manifest.getAbsolutePath());
// assume there is one rule engine instance per running service
// start a new rule engine and store it in a HashTable
RulesEngine rle = new RulesEngine(this);
// "load" the rule engine into the FSM
fsm.loadRuleEngine(rle);
// Before creating the service, check the service name is unique.
String customer = customerFqn.substring(customerFqn
.indexOf("customers"));
String parts[] = customer.split("\\.");
customer = parts[1];
serviceName = checkServiceName(customer, serviceName);
fsm.init(serviceName, customer);
fsm.start();
ruleEngineVector.put(fsm.getServiceFQN(), rle);
// Store the mapping from FSM FQN to this LCC
service2Controller.put(fsm.getServiceFQN(), String.valueOf(count++));
// GENERATE CONTROL EVENT TO ACTUALLY START THE SERVICE
SMControlEvent controlEvent = new SMControlEvent(0, 0, null, "start",
fsm.getServiceFQN().toString());
controlEvent.setControlEventType(SMControlEvent.START_SERVICE);
this.putEvent(controlEvent);
return fsm.getServiceFQN();
}
/**
* Deploys the Service application defined in the manifest passed as a
* parameter.
*
* @param manifest
* XML code containing the description of the Service
* Application.
*
* @param customer
* String identifier of the custumer deploying the service
*
* @return
*/
public FQN deploy(String manifest, String customer, String serviceName) {
String fileName = new String(manifestBuffer
+ Integer.toString(deploymentNum) + ".xml");
deploymentNum++;
BufferedWriter out;
try {
out = new BufferedWriter(new FileWriter(fileName));
out.write(manifest);
out.close();
} catch (IOException ex) {
java.util.logging.Logger.getLogger(
LifecycleController.class.getName()).log(
java.util.logging.Level.SEVERE, null, ex);
}
logger.info("Deploying manifest file ");
File bufferedFile = new File(fileName);
return deploy(bufferedFile, customer, serviceName);
}
public void reconfig(FQN serviceID) {
throw new UnsupportedOperationException("Not supported yet.");
}
public void undeploy(FQN serviceID) {
// create a SMCOntrolEvent of the UNDEPLOY_SERVICE subtype and put it in
// the appropriate queue
SMControlEvent undeploy = new SMControlEvent(0, 0, null, "undeploy",
serviceID.toString());
undeploy.setControlEventType(SMControlEvent.UNDEPLOY_SERVICE);
// put event into the apporpiate queue
this.putEvent(undeploy);
}
/**
* Method invoked by the SP to set the desired frequency for the monitoring
* events of a given service
*
* @param serviceID
* @param period
*/
public void setFrequency(FQN serviceID, long period) {
((FSM) fsmVector.get(serviceID)).setMonFreq(period);
}
/**
* Method invoked by the AllEventListener whenever a new Event is received
* in the EventBus
*
* @param event
*/
@SuppressWarnings("unchecked")
public void onEvent(Event event) {
if (state != LccStates.RUNNING)
return;
monitoringLog.info("Event reached Lifecycle controller: "
+ event.toString());
FQN deployObject;
// possible Hw items in the deployment model
CPU cpu;
Disk disk;
Memory mem;
NIC nic;
// service KPI value
ServiceKPI sKpi;
// probe KPI
ProbeKPI pKpi;
// whenever an Event has been received cast the event to determine the
// event type
EventType eventType = event.getEventType();
switch (eventType) {
case SM_CONTROL_EVENT:
SMControlEvent smce = (SMControlEvent) event;
logger
.info("External event received: "
+ smce.getSuggestedAction());
this.putEvent(smce);
break;
case VEE_HW_MEASUREMENT:
// create a FQN to get the appropriate object in the Directory
VeeHwMeasureEvent hwEvent;
hwEvent = (VeeHwMeasureEvent) event;
Object object = ReservoirDirectory.getInstance().getObject(
new FQN(hwEvent.getMeasure()));
if (object == null) {
monitoringLog
.error("Not object registered in directory with name "
+ hwEvent.getMeasure());
Set<FQN> fqns = ReservoirDirectory.getInstance()
.matchingNamesAndChildrenRegistered(
ReservoirDirectory.getInstance()
.getRootNameSpace());
if (fqns.isEmpty())
monitoringLog.error("NOT FQNs registered!");
else {
}
break;
} else if (object instanceof CPU) {
cpu = (CPU) object;
cpu.setUsage((float) hwEvent.getValue());
monitoringLog.info("CPU usage updated: "
+ (float) hwEvent.getValue());
} else if (object instanceof Disk) {
disk = (Disk) object;
disk.setFreeCapacity((int) hwEvent.getValue());
logger
.info("Disk usage updated: "
+ (float) hwEvent.getValue());
} else if (object instanceof Memory) {
mem = (Memory) object;
mem.setFreeMem((int) hwEvent.getValue());
monitoringLog.info("Memory usage updated: "
+ (float) hwEvent.getValue());
} else if (object instanceof NIC) {
nic = (NIC) object;
nic.setThroughput((int) hwEvent.getValue());
monitoringLog.info("NIC usage updated: "
+ (float) hwEvent.getValue());
}
if (object != null && SMConfiguration.getInstance().isWasupActive()) {
try {
wasupClient.postMeasure((DirectoryEntry) object, String
.valueOf(hwEvent.getValue()));
} catch (IOException e) {
monitoringLog
.error("Measure could not be post due to an IO error: "
+ e.getMessage());
} catch (JSONException e) {
monitoringLog
.error("Measure may have not been posted, due to an error in the response: "
+ e.getMessage());
} catch (Throwable e) {
monitoringLog.error("Unknow error connecting to WASUP: "
+ e.getMessage(), e);
}
}
break;
case AGENT_MEASUREMENT:
AgentMeasureEvent agentEvent;
agentEvent = (AgentMeasureEvent) event;
// create a FQN to get the appropriate object in the Directory
deployObject = new FQN(agentEvent.getMeasure());
sKpi = (ServiceKPI) ReservoirDirectory.getInstance().getObject(
deployObject);
if (sKpi == null) {
monitoringLog
.error("Not KPI registered in directory with name "
+ deployObject);
} else {
sKpi.setKPIValue(agentEvent.getValue());
if (SMConfiguration.getInstance().isWasupActive())
try {
wasupClient.postMeasure(sKpi, String.valueOf(agentEvent
.getValue()));
} catch (IOException e) {
monitoringLog
.error("Measure could not be post due to an IO error: "
+ e.getMessage());
} catch (JSONException e) {
monitoringLog
.error("Measure may have not been posted, due to an error in the response: "
+ e.getMessage());
} catch (Throwable e) {
monitoringLog.error(
"Unknow error connecting to WASUP: "
+ e.getMessage(), e);
}
monitoringLog.info("Updated KPI " + deployObject.toString()
+ " with value " + sKpi.getKPIValue());
}
break;
case PROBE_MEASUREMENT:
ProbeMeasureEvent probeEvent;
probeEvent = (ProbeMeasureEvent) event;
// create a FQN to get the appropriate object in the Directory
deployObject = new FQN(probeEvent.getMeasure());
pKpi = (ProbeKPI) ReservoirDirectory.getInstance().getObject(
deployObject);
if (pKpi == null) {
monitoringLog
.error("Not KPI registered in directory with name "
+ deployObject);
} else {
pKpi.setKPIValue(probeEvent.getValue());
monitoringLog.info("Updated KPI " + deployObject.toString()
+ " with value " + pKpi.getKPIValue());
}
break;
case SMI_CHANNEL_EVENT:
SMIChannelEvent smiEvent = (SMIChannelEvent) event;
processSmiEvent(smiEvent);
break;
case ADMINISTRATIVE_EVENT:
AdministrativeEvent adminEvent = (AdministrativeEvent) event;
processAdminEvent(adminEvent);
break;
default:
throw new Error("Unkonwn event type???");
}
}
private void processAdminEvent(AdministrativeEvent event) {
logger.info("Processing Administration Event");
AdministrativeEvent response;
switch (event.getCommand()) {
case STOP:
finish();
break;
case NETWORKRANGE:
switch (event.getSubcommand()) {
case CREATE:
logger
.info("Creating new Network Range: "
+ event.getPayload());
loadNetworkAddress(event.getPayload());
break;
case REMOVE:
logger.info("Removing Network Range: " + event.getPayload());
NetworkRange selectedNr = null;
for (NetworkRange nr : networkRanges)
if (nr.getIP().equals(event.getPayload()))
selectedNr = nr;
if (selectedNr != null && selectedNr.getSubnets().size() == 0)
networkRanges.remove(selectedNr);
break;
}
break;
case STATUS:
logger.info("Sending internal status");
response = new AdministrativeEvent(System.currentTimeMillis(), 0,
AdministrativeEvent.CommandType.STATUS);
StringBuffer payload = new StringBuffer();
payload.append("<SLM state=\"" + state.toString() + "\" >\n");
payload.append("<DeployedServices>\n");
for (FSM fsmItr : fsmVector.values()) {
payload.append("<Service fqn=\"" + fsmItr.getServiceFQN()
+ "\" state=\"" + fsmItr.getStateText() + "\" />\n");
}
payload.append("</DeployedServices>\n");
payload.append("<NetworkRanges>\n");
for (NetworkRange nr : networkRanges) {
payload.append(nr);
}
payload.append("</NetworkRanges>\n");
payload.append("</SLM>\n");
response.setPayload(payload.toString());
try {
busMediator.sendEvent(response, null);
} catch (JMSException e1) {
logger.error("Bus communication exception: " + e1.getMessage());
}
break;
}
}
@SuppressWarnings("serial")
private void processSmiEvent(SMIChannelEvent event) {
logger.info("Processing a SMI Event");
SMIChannelEvent e;
ServiceApplication sa;
VEE vee;
Document doc = null;
DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = null;
try {
docBuilder = dbfac.newDocumentBuilder();
} catch (ParserConfigurationException e3) {
// TODO Auto-generated catch block
e3.printStackTrace();
}
doc = docBuilder.newDocument();
switch (event.getAction()) {
case GET_ORG:
System.out.println("get org");
final String fqnOrgGet = event.get(SMIChannelEvent.FQN_ID);
String org = URICreation.getOrg(fqnOrgGet);
logger.info("Org obtained " + org);
// final String seqNumberGetOrg =
// event.get(SMIChannelEvent.SEQUENCE_NUMBER);
e = new SMIChannelEvent(System.currentTimeMillis(), 0,
SMIAction.GET_ORG);
if (!SMConfiguration.getInstance().getSiteRoot().equals(org)) {
logger.error("The Org id " + org
+ " does not belong to the site deployed ");
e.setSuccess(false);
} else {
// List<Customer> customers =
// DbManager.getDbManager().getList(Customer.class);
doc = getOrganizationXML(this.customers);
final String xmlOrgRepresentation = DataTypesUtils
.serializeXML(doc);
System.out.println("xml file " + xmlOrgRepresentation);
e.put(SMIChannelEvent.ORG_DESCRIPTION, xmlOrgRepresentation);
e.setSuccess(true);
}
try {
busMediator.sendEvent(e, new HashMap<String, String>() {
{
put("org", fqnOrgGet);
put("action", SMIAction.GET_VDC.toString());
// put(SMIChannelEvent.SEQUENCE_NUMBER,
// seqNumberGetOrg);
}
});
} catch (JMSException e1) {
logger.error("Bus communication exception: " + e1.getMessage());
}
break;
case DEPLOY:
try {
FQN name = deploy(event.get(SMIChannelEvent.OVF_DOCUMENT),
event.get(SMIChannelEvent.CUSTOMER_NAME), event
.get(SMIChannelEvent.SERVICE_NAME));
e = new SMIChannelEvent(System.currentTimeMillis(), 0,
SMIAction.DEPLOY);
e.put(SMIChannelEvent.FQN_ID, name.toString());
e.setSuccess(true);
final String customerName = event
.get(SMIChannelEvent.CUSTOMER_NAME);
try {
busMediator.sendEvent(e, new HashMap<String, String>() {
{
put("customer", customerName);
put("action", SMIAction.DEPLOY.toString());
}
});
} catch (JMSException e1) {
logger.error("Bus communication exception: "
+ e1.getMessage());
}
} catch (Exception ex) {
e = new SMIChannelEvent(System.currentTimeMillis(), 0,
SMIAction.DEPLOY);
e.put(SMIChannelEvent.FQN_ID, "");
e.setSuccess(false);
e.setMessage("Exception deploying service: " + e.getMessage());
final String customerName = event
.get(SMIChannelEvent.CUSTOMER_NAME);
try {
busMediator.sendEvent(e, new HashMap<String, String>() {
{
put("customer", customerName);
put("action", SMIAction.DEPLOY.toString());
}
});
} catch (JMSException e1) {
logger.error("Bus communication exception: "
+ e1.getMessage());
}
}
break;
case DEPLOY_VDC:
final String dd = event.get(SMIChannelEvent.FQN_ID);
String org3 = URICreation.getOrg(dd);
logger.info("Org obtained " + org3);
// final String seqNumberGetOrg =
// event.get(SMIChannelEvent.SEQUENCE_NUMBER);
e = new SMIChannelEvent(System.currentTimeMillis(), 0,
SMIAction.GET_ORG);
e.setSuccess(false);
System.out.println("Sucess");
/*
* System.out.println ("llego evento"); String orga =
* event.get(SMIChannelEvent.ORG_DESCRIPTION); String customerName =
* event.get(SMIChannelEvent.CUSTOMER_NAME); System.out.println
* ("orga " + orga + customerName); String customerfqn =
* URICreation.getFQN(orga, customerName); FQN customerFQN = new FQN
* (customerfqn);
*
* if
* (ReservoirDirectory.getInstance().isNameRegistered(customerFQN))
* { logger.info("Customer already present: " +
* customerFQN.toString()); Customer client = (Customer)
* ReservoirDirectory.getInstance().getObject(customerFQN); } else {
* logger.info("New customer: " + customerFQN.toString() +
* ", registering in directory"); Customer client = new
* Customer(customerName);
* ReservoirDirectory.getInstance().registerObject(client.getFQN(),
* client); DbManager.getDbManager().save(client); }
*
* e = new SMIChannelEvent(System.currentTimeMillis(), 0,
* SMIAction.GET_ORG); e.setSuccess(false); System.out.println
* ("Sendind event");
*/
/*
* e = new SMIChannelEvent(System.currentTimeMillis(), 0,
* SMIAction.DEPLOY_VDC); e.put(SMIChannelEvent.FQN_ID, "");
* e.setSuccess(true); System.out.println ("Sucess");
*/
break;
case UNDEPLOY:
undeploy(new FQN(event.get(SMIChannelEvent.FQN_ID)));
e = new SMIChannelEvent(System.currentTimeMillis(), 0,
SMIAction.UNDEPLOY);
final String serviceName = event.get(SMIChannelEvent.FQN_ID);
try {
busMediator.sendEvent(e, new HashMap<String, String>() {
{
put("service", serviceName);
put("action", SMIAction.UNDEPLOY.toString());
}
});
} catch (JMSException e1) {
logger.error("Bus communication exception: " + e1.getMessage());
}
FQN servFQN = new FQN(event.get(SMIChannelEvent.FQN_ID));
ServiceApplication serv = (ServiceApplication) ReservoirDirectory
.getInstance().getObject(servFQN);
Customer cust = serv.getCustomer();
if (cust.isServiceRegistered(serv)) {
cust.unregisterService(serv);
}
ReservoirDirectory.getInstance().removeMatchingNames(servFQN);
// Removes the customer if it has no more services
if (cust.getServices().isEmpty()) {
ReservoirDirectory.getInstance().removeMatchingNames(
cust.getFQN());
this.customers.remove(cust);
}
break;
case GET_VAPP:
final String serviceFQN = event.get(SMIChannelEvent.FQN_ID);
e = new SMIChannelEvent(System.currentTimeMillis(), 0,
SMIAction.GET_VAPP);
boolean success = false;
try {
sa = getApplication(new FQN(event.get(SMIChannelEvent.FQN_ID)));
if (sa != null) {
doc = sa.toXML();
success = true;
}
} catch (RemoteException e2) {
logger
.error("Error obtaining the Service application from its FQN: "
+ e2.getMessage());
}
if (!success) {
Element element = null;
try {
Element r = doc.createElement("ErrorSet");
doc.appendChild(r);
Element unknown = doc.createElement("UnknownElements");
r.appendChild(unknown);
element = doc.createElement("element");
unknown.appendChild(element);
element.setAttribute("type", "vapp");
element.setAttribute("ref", "http://"
+ SMConfiguration.getInstance().getSMIHost() + ":"
+ SMConfiguration.getInstance().getSMIPort() + "/"
+ URICreation.getURIService(serviceFQN));
} catch (IllegalArgumentException iae) {
element.appendChild(doc.createElement(event
.get(SMIChannelEvent.FQN_ID)));
}
}
final String xmlRepresentation = DataTypesUtils.serializeXML(doc);
e.put(SMIChannelEvent.SERVICE_DESCRIPTION, xmlRepresentation);
try {
busMediator.sendEvent(e, new HashMap<String, String>() {
{
put("service", serviceFQN);
put("action", SMIAction.GET_VAPP.toString());
}
});
} catch (JMSException e1) {
logger.error("Bus communication exception: " + e1.getMessage());
}
break;
case GET_VEE:
final String veeFQN = event.get(SMIChannelEvent.FQN_ID);
e = new SMIChannelEvent(System.currentTimeMillis(), 0,
SMIAction.GET_VEE);
success = false;
try {
vee = getVee(new FQN(event.get(SMIChannelEvent.FQN_ID)));
if (vee != null) {
doc = vee.toXML();
success = true;
}
} catch (RemoteException e2) {
logger.error("Error obtaining the VEE from its FQN: "
+ e2.getMessage());
}
if (!success) {
Element r = doc.createElement("ErrorSet");
doc.appendChild(r);
Element unknown = doc.createElement("UnknownElements");
r.appendChild(unknown);
Element element = doc.createElement("element");
unknown.appendChild(element);
element.setAttribute("type", "vapp");
try {
element.setAttribute("ref", "http://"
+ SMConfiguration.getInstance().getSMIHost() + ":"
+ SMConfiguration.getInstance().getSMIPort() + "/"
+ URICreation.getURIService(veeFQN));
} catch (IllegalArgumentException iae) {
element.appendChild(doc.createElement(event
.get(SMIChannelEvent.FQN_ID)));
}
}
String xml = DataTypesUtils.serializeXML(doc);
e.put(SMIChannelEvent.VEE_DESCRIPTION, xml);
try {
busMediator.sendEvent(e, new HashMap<String, String>() {
{
put("vee", veeFQN);
put("action", SMIAction.GET_VEE.toString());
}
});
} catch (JMSException e1) {
logger.error("Bus communication exception: " + e1.getMessage());
}
break;
case GET_VDC:
try {
cust = ((Customer) ReservoirDirectory.getInstance().getObject(
new FQN(event.get(SMIChannelEvent.FQN_ID))));
e = new SMIChannelEvent(System.currentTimeMillis(), 0,
SMIAction.GET_VDC);
// DocumentBuilderFactory dbfac =
// DocumentBuilderFactory.newInstance();
// DocumentBuilder docBuilder;
docBuilder = dbfac.newDocumentBuilder();
doc = docBuilder.newDocument();
if (cust != null) {
Element r = doc.createElement("VDC");
doc.appendChild(r);
r.setAttribute("name", cust.getCustomerName());
for (ServiceApplication srvApp : cust.getServices()) {
Element link = (Element) doc.createElement("Link");
link.setAttribute("rel", "down");
link.setAttribute("type",
"application/vnd.telefonica.tcloud.vapp+xml");
// link.setAttribute("href", "http://" +
// SMConfiguration.getInstance().getSMIHost() + ":" +
// SMConfiguration.getInstance().getSMIPort() + "/" +
// URICreation.getURIService(srvApp.getFQN().toString()));
link.setAttribute("href", "@HOSTNAME"
+ URICreation.getURIService(srvApp.getFQN()
.toString()));
r.appendChild(link);
}
} else {
Element r = doc.createElement("ErrorSet");
doc.appendChild(r);
Element unknown = doc.createElement("UnknownElements");
r.appendChild(unknown);
Element element = doc.createElement("element");
unknown.appendChild(element);
element.setAttribute("type", "vdc");
try {
element.setAttribute("ref", "http://"
+ SMConfiguration.getInstance().getSMIHost()
+ ":"
+ SMConfiguration.getInstance().getSMIPort()
+ "/"
+ URICreation.getVDC(event
.get(SMIChannelEvent.FQN_ID)));
} catch (IllegalArgumentException iae) {
element.appendChild(doc.createElement(event
.get(SMIChannelEvent.FQN_ID)));
}
}
doc.normalizeDocument();
final String xmlCustomerRepresentation = DataTypesUtils
.serializeXML(doc);
final String customer = event.get(SMIChannelEvent.FQN_ID);
e.put(SMIChannelEvent.CUSTOMER_DESCRIPTION,
xmlCustomerRepresentation);
try {
busMediator.sendEvent(e, new HashMap<String, String>() {
{
put("customer", customer);
put("action", SMIAction.GET_VAPP.toString());
}
});
} catch (JMSException e1) {
logger.error("Bus communication exception: "
+ e1.getMessage());
}
} catch (ParserConfigurationException ex) {
}
break;
default:
}
}
/**
* SMI implemented method. allows the SM servlet to get the sap of a given
* service to later communicate with the gadgets and show the SP all the
* information
*
* @param serviceID
* @return
* @throws java.rmi.RemoteException
*/
/*
* public ServiceApplication getApplication(FQN serviceID) throws
* RemoteException { // it looks for the SAP into the ReservoirDirectory //
* this could obviously have been done by the servlet itself // but in the
* near future they both may dwell on different machines and this method
* actually invoked through RMI calls return
* ((ServiceApplication)ReservoirDirectory
* .getInstance().getObject(serviceID)); }
*/
/**
* SMI implemented method. allows the SM servlet to get the VEE of a given
* service to later communicate with the gadgets and show the SP all the
* information
*
* @param veeID
* @return
* @throws java.rmi.RemoteException
*/
public VEE getVee(FQN veeID) throws RemoteException {
// it looks for the SAP into the ReservoirDirectory
// this could obviously have been done by the servlet itself
// but in the near future they both may dwell on different machines and
// this method actually invoked through RMI calls
return ((VEE) ReservoirDirectory.getInstance().getObject(veeID));
}
public ServiceApplication getApplication(FQN serviceID)
throws RemoteException {
// it looks for the SAP into the ReservoirDirectory
// this could obviously have been done by the servlet itself
// but in the near future they both may dwell on different machines and
// this method actually invoked through RMI calls
return ((ServiceApplication) ReservoirDirectory.getInstance()
.getObject(serviceID));
}
/**
* Check all the available network ranges for a network address meeting the
* size requirements. If a suitable network is not found, returns null.
*
* @param size
* Minimum size of the network (number of hosts)
*
* @param publicNetwork
* Whether the returned address should be public or not.
*/
public String[] getNetworkAddress(long size, boolean publicNetwork) {
logger.info("Asking LCC for a "
+ ((publicNetwork) ? "public" : "private")
+ " network of size: " + size);
for (NetworkRange nr : networkRanges) {
if (nr.isPublic() != publicNetwork)
continue;
logger.info("Triying to get Network from range: " + nr.getIP());
String[] address = nr.getNetwork(size);
if (address != null) {
String[] result = new String[] { address[0], address[1],
nr.getDNS(), nr.getGateway() };
logger.info("Network leased: [address=" + result[0] + ", mask="
+ result[1] + ", dns=" + result[2] + ", gateway="
+ result[3]);
// Save the network ranges
logger.info("Saving network information.");
DbManager.getDbManager().save(nr);
return result;
}
logger.info("No subnetwork could be leased");
}
logger.error("No suitable network could be created.");
return null;
}
/**
* Returns an IP address for a host, belonging to the specified network.
*
* @param network
* Target network.
*
* @return An IP address belonging to the target network if there was one
* available. null otherwise. Note that the method doesn't make a
* difference between the case where there are no IPs left on the
* desired network and the one in which the network itself doesn't
* belong to any of the actual ranges of the LCC.
*/
public String getHostAddress(String network, String staticIpProp) {
logger.info("Asking LCC for a host address on network: " + network);
for (NetworkRange nr : networkRanges) {
if (nr.isNetworkInRange(network)) {
String ipLeased = nr.getNetworkAddress(network, staticIpProp);
logger.info("IP address [" + ipLeased + "] leased");
// Save the network ranges
logger.info("Saving network information.");
DbManager.getDbManager().save(nr);
return ipLeased;
}
}
logger.error("No host address could be leased");
return null;
}
public void releaseHostAddress(String ip, String network) {
logger.info("Releasing host address [" + ip + "] on network ["
+ network + "]");
for (NetworkRange nr : networkRanges) {
if (nr.isNetworkInRange(network)) {
nr.releaseAddress(ip, network);
// Save the network ranges
logger.info("Saving network information.");
DbManager.getDbManager().save(nr);
break;
}
}
}
/**
* Prepares the SLM to be stopped. Save the state when appropiate, stop all
* the services and undeploy them.
*/
public void finish() {
logger.info("LCC changing to FINISHING state.");
state = LccStates.FINISHING;
if (SMConfiguration.getInstance().isUndeployOnServertopFlagSet()) {
// Tell all the FSMs to undeploy its services.
for (String fqn : fsmVector.keySet()) {
undeploy(new FQN(fqn));
}
// Wait for the threads to orderly join its parent.
for (String fqn : fsmVector.keySet()) {
FSM machine = fsmVector.get(fqn);
try {
machine.join(FSM_FINISH_TIMEOUT);
} catch (InterruptedException e) {
logger
.error("SLM interrupted while waiting for FSM finishing.");
}
if (machine.isAlive()) {
logger
.warn("Service ["
+ fqn
+ "] did not stop on time. It will be killed on exit.");
}
}
}
logger.info("LCC finished");
System.exit(0);
}
public static Document getOrganizationXML(List<Customer> vdcList) {
DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder;
dbfac.setNamespaceAware(true);
try {
docBuilder = dbfac.newDocumentBuilder();
Document doc = docBuilder.newDocument();
Element r = doc.createElement("Org");
doc.appendChild(r);
r.setAttribute("name", getSiteRoot());
// r.setAttribute("href", "http://" +
// SMConfiguration.getInstance().getSMIHost() + ":" +
// SMConfiguration.getInstance().getSMIPort() +
// URICreation.getURIOrg(siteRoot));
r.setAttribute("href", "@HOSTNAME"
+ URICreation.getURIOrg(getSiteRoot()));
for (Customer vDatacenter : vdcList) {
Element link = (Element) doc.createElement("Link");
link.setAttribute("rel", "down");
link.setAttribute("type",
"application/vnd.telefonica.tcloud.vdc+xml");
link.setAttribute("href", "@HOSTNAME"
+ URICreation
.getURIVDC(vDatacenter.getFQN().toString()));
r.appendChild(link);
}
Element vdcAddlink = (Element) doc.createElement("Link");
vdcAddlink.setAttribute("rel", "add");
vdcAddlink.setAttribute("type",
"application/vnd.telefonica.tcloud.vdc+xml");
vdcAddlink.setAttribute("href", "@HOSTNAME"
+ URICreation.URI_VDC_ADD.replace("{org-id}", getSiteRoot()
.replace(".", "_")));
r.appendChild(vdcAddlink);
Element link = (Element) doc.createElement("Link");
link.setAttribute("rel", "tasks");
link.setAttribute("type",
"application/vnd.telefonica.tcloud.tasklist+xml");
link.setAttribute("href", "@HOSTNAME"
+ URICreation.getURIOrg(getSiteRoot()) + "/task");
r.appendChild(link);
return doc;
} catch (ParserConfigurationException e) {
e.printStackTrace();
return null;
}
}
private static String getSiteRoot() {
String siteRoot = null;
if (siteRoot == null) {
siteRoot = ReservoirDirectory.ROOT_NAME_SPACE;
}
return siteRoot;
}
public void addCustomer(Customer client) {
this.customers.add(client);
}
}