/* * 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.File; import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; import java.io.InvalidClassException; import java.io.PrintWriter; import java.io.Serializable; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import javax.xml.bind.JAXBException; import org.apache.log4j.Logger; import org.dmtf.schemas.ovf.envelope._1.VirtualSystemType; import org.json.JSONException; import com.abiquo.ovf.exceptions.XMLException; import com.telefonica.claudia.configmanager.ConfiguratorFactory; import com.telefonica.claudia.configmanager.lb.LoadBalancerConfigurator; 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.Rule; import com.telefonica.claudia.slm.deployment.ServiceApplication; import com.telefonica.claudia.slm.deployment.ServiceKPI; import com.telefonica.claudia.slm.deployment.VEE; 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.DiskConf; import com.telefonica.claudia.slm.deployment.hwItems.NIC; import com.telefonica.claudia.slm.deployment.hwItems.NICConf; import com.telefonica.claudia.slm.deployment.hwItems.Network; import com.telefonica.claudia.slm.deployment.paas.Product; import com.telefonica.claudia.slm.eventsBus.events.SMControlEvent; import com.telefonica.claudia.slm.maniParser.ManiParserException; import com.telefonica.claudia.slm.maniParser.Parser; import com.telefonica.claudia.slm.monitoring.MonitoringRestBusConnector; import com.telefonica.claudia.slm.monitoring.WasupHierarchy; import com.telefonica.claudia.slm.naming.FQN; import com.telefonica.claudia.slm.naming.ReservoirDirectory; import com.telefonica.claudia.slm.paas.Monitoring; import com.telefonica.claudia.slm.paas.OVFContextualization; import com.telefonica.claudia.slm.paas.PaasUtils; import com.telefonica.claudia.slm.paas.vmiHandler.MonitoringClient; import com.telefonica.claudia.slm.paas.vmiHandler.NUBAMonitoringClient; import com.telefonica.claudia.slm.paas.vmiHandler.PlacementModuleClient; import com.telefonica.claudia.slm.paas.vmiHandler.RECManagerClient; import com.telefonica.claudia.slm.report.MonitoringReportObtainKPI; import com.telefonica.claudia.slm.report.ReportKPIValue; import com.telefonica.claudia.slm.rulesEngine.RulesEngine; import com.telefonica.claudia.slm.serviceconfiganalyzer.ServiceConfigurationAnalyzer; import com.telefonica.claudia.slm.vmiHandler.TCloudClient; import com.telefonica.claudia.slm.vmiHandler.VEEReplicaAllocationResult; import com.telefonica.claudia.slm.vmiHandler.VEEReplicaUpdateResult; import com.telefonica.claudia.slm.vmiHandler.VMIHandler; import com.telefonica.claudia.slm.vmiHandler.VMIHandler.SubmissionModelType; import com.telefonica.claudia.slm.vmiHandler.exceptions.AccessDeniedException; import com.telefonica.claudia.slm.vmiHandler.exceptions.CommunicationErrorException; import com.telefonica.claudia.slm.vmiHandler.exceptions.NotEnoughResourcesException; import com.telefonica.claudia.slm.vmiHandler.exceptions.VEEReplicaDescriptionMalformedException; /** * The FSM (Finite State Machine) manages the lifecycle of a single service. FSM * is a runnable class, that is started by the LCC. * * The service lifecycle, represented by the run() method, consists of an * event-consuming loop. Each service has a matching event queue in the LCC, * where all the control events are enqueued. In each step of the lifecycle, a * new event is pulled out of the queue and treated in the getNextState() * method. This method will transition the FSM to the appropiate state after any * completed action. * * When a service is created, first of all the init() method is called (INIT * state). In this method, all the needed clients are created and the OVF * descriptor is parsed so all the information about the service is translated * into a class hierarchy of classes in the deployment package. Once it is * parsed, the Service transitions to the SPECIFIED state where the service will * be really deployed. */ public class FSM extends Thread implements Serializable { private static final long serialVersionUID = -8902978852760714189L; private static Logger logger = Logger.getLogger("Service"); // Internal state information // -------------------------------------------------------------------------------------------- @SuppressWarnings("unused") private long monitFreq = 1000; /** * This flag should be set for this situations that causa a non-recoverable * error. It leads the machine automatically to the ERROR state. */ private boolean abort = false; /** * This message will be printed in the abort message of the FSM to be able * to recognize the problem that lead the FSM to abort its execution. */ private String abortMessage = null; /** * Determines whether the Finite state machine should continue its execution * or not. */ private boolean finishExecution = false; /** * Whenever an elasticity rule is fired (and so a creation or removement of * a replica), the timestamps of the beginning and ending of this action are * stored in this interval (the beginning in the first member of the array, * the ending in the last one) for each vee. If an event is recieved to * create or deploy a replica, the timestamp of the event is checked against * the interval for this veee, so to avoid creating more than one replica * due to the same load increment (this situation will happen whenever the * monitoring period is greater than the time needed to make one of those * actions). */ public Map<VEE, long[]> lastElasticityInterval = new HashMap<VEE, long[]>(); /** * Margin under and over the elasticity interval, to prevent events out of * order to fire actions supposed to be prevented by the elasticity interval * (the interval is calculated with the timestamp of the event firing the * action), and to let the deployed or removed replica affect the real load * of the service before reevaluating the need of doing some action. */ private final static long ELASTICITY_MARGIN = 60 * 1000; // State-related information // -------------------------------------------------------------------------------------------- private int currentState, nextState;; public static final int numStates = 6; public static final int NONE = 0; public static final int INIT = 1; public static final int RUNNING = 2; public static final int ERROR = 3; public static final int RECONFIGURED = 4; public static final int FINISHED = 5; public static final int POLLING = 6; /** * Determines the polling frequency the FSM will use to check the event * buffer. */ private static final long POLLING_PERIOD = 1000; // Service related information // -------------------------------------------------------------------------------------------- /** * Service application the FSM manages. */ public ServiceApplication sap; /** * URL of the OVF Descriptor used to deploy the service. */ private String xmlFile = ""; /** * Scale up and down factors. */ public float scaleUpPercentage; public float scaleDownPercentage; /** * Lazy scale down time. */ public int lazyScaleDownTime; // VEE Related information // ------------------------------------------------------------------------------------------- /** * Array containing the vees. Is exactly the same information we have in * vees. * * TODO: Is this synchronized with the hashset? */ private VEE[] veeArray; /** * Set with the currently deployed replicas. */ private Set<VEEReplica> veesRollBack = new HashSet<VEEReplica>(); /** * Set of nics used to deploy the service. It will be used to properly * undeploy them once the service has finished. */ Set<Network> nicsToDeploy; // Internal references to other blocks of the SM // -------------------------------------------------------------------------------------------- /** * Reference to the Lifecycle Controller that created the FSM (also the one * who have the evente queue). */ private LifecycleController lcc; public RulesEngine rle; /** * OVF Parser. The parser is used for two kinds of actions: it is used first * time the service is deployed to create the class hierarchy of the service * components; and its also used to generate the OVF environment for each * replica once it is deployed (whether it is the first deployement or a * elasticity action). */ public Parser parser; /** * VMI client used to comunicate with the underlying layer in order to * deploy replicas and other resources. */ public VMIHandler vmi = null; // Deployment information // -------------------------------------------------------------------------------------------- private static final String repositoryDir = "./repository"; private static final String customImagesDir = repositoryDir + SMConfiguration.getInstance().getImagesServerPath(); private static final String protocol = "http://"; /** * Monitoring client for the service. It holds the hierarchy of measurement * types for this service and also acts as the client for client * interactions with Wasup (whenever a measurement reaches de SM it is * redirected to Wasup for data mining). */ private Monitoring claudiaMonitoring; private boolean setSwap = false; /** * Property map defining the customization info for the vees. * * TODO: it seems strange to have the same customization information for all * the types of vees. TODO: this seems more appropiate as a local attribute * in the getNextState method. */ private HashMap<String, String> replicaCustomInfo; private LoadBalancerConfigurator lbConfigurator; /** * Determines the kind of events permitted in each of the different FSM * states. The key of the map represents the state and the value is a list * of the accepted events. */ private static Map<Integer, List<Integer>> stateEventMatrix = new HashMap<Integer, List<Integer>>(); static { stateEventMatrix.put(NONE, new ArrayList<Integer>()); stateEventMatrix.put(INIT, new ArrayList<Integer>()); stateEventMatrix.get(INIT).add(SMControlEvent.START_SERVICE); stateEventMatrix.put(RUNNING, new ArrayList<Integer>()); stateEventMatrix.get(RUNNING).add( SMControlEvent.ELASTICITY_RULE_VIOLATION); stateEventMatrix.get(RUNNING).add(SMControlEvent.NEW_RULE_ADDED); stateEventMatrix.get(RUNNING).add(SMControlEvent.RULE_CHANGED); stateEventMatrix.get(RUNNING).add(SMControlEvent.UNDEPLOY_SERVICE); stateEventMatrix.get(RUNNING).add(SMControlEvent.GET_MONITORING_DATA); stateEventMatrix.put(ERROR, new ArrayList<Integer>()); stateEventMatrix.put(RECONFIGURED, new ArrayList<Integer>()); stateEventMatrix.put(FINISHED, new ArrayList<Integer>()); stateEventMatrix.put(POLLING, new ArrayList<Integer>()); } public FSM(LifecycleController lcc, String endPoint) { this.lcc = lcc; currentState = NONE; nextState = currentState; try { this.lbConfigurator = ConfiguratorFactory.getInstance() .createConfigManager(LoadBalancerConfigurator.class); } catch (InvalidClassException e) { logger.fatal("Invalid Configurator", e); } } public FSM() { try { this.lbConfigurator = ConfiguratorFactory.getInstance() .createConfigManager(LoadBalancerConfigurator.class); } catch (InvalidClassException e) { logger.fatal("Invalid Configurator", e); } } public int getCurrentState() { return this.currentState; } public String getStateText() { switch (currentState) { case NONE: return "NONE"; case INIT: return "INIT"; case RUNNING: return "RUNNING"; case ERROR: return "ERROR"; case RECONFIGURED: return "RECONFIGURED"; case FINISHED: return "FINISHED"; case POLLING: return "POLLING"; default: return "UNKNOWN"; } } public void loadManifest(String mani) { this.xmlFile = mani; } public void loadRuleEngine(RulesEngine rulesEngine) { rle = rulesEngine; } /** * Method for the LCC to set the monitoring frequency upon SP request. */ protected void setMonFreq(long freq) { monitFreq = freq; } @SuppressWarnings("unchecked") public void registerInDirectory() { VEE vee; Rule rule; ServiceKPI kpi; logger.info("Service Application: " + sap.getSerAppName()); Set<VEE> veeVector = sap.getVEEs(); Set<Rule> ruleVector = sap.getServiceRules(); Set<ServiceKPI> kpiVector = sap.getServiceKPIs(); // Register ServiceApp ReservoirDirectory.getInstance().registerObject(sap.getFQN(), sap); // add VEEs to Service Iterator veeIterator = veeVector.iterator(); if (!veeIterator.hasNext()) logger.info("No VEEs defined"); while (veeIterator.hasNext()) { vee = (VEE) veeIterator.next(); logger.info("VEE " + vee.getVEEName()); ReservoirDirectory.getInstance().registerObject(vee.getFQN(), vee); } // add KPIs Iterator kpiIterator = kpiVector.iterator(); if (!kpiIterator.hasNext()) logger.info("No KPIs defined"); while (kpiIterator.hasNext()) { kpi = (ServiceKPI) kpiIterator.next(); logger.info("KPI " + kpi.getKPIName()); System.out.println ("storing " +kpi.getFQN()); ReservoirDirectory.getInstance().registerObject(kpi.getFQN(), kpi); } // add Rules Iterator ruleIterator = ruleVector.iterator(); if (!ruleIterator.hasNext()) logger.info("No Rules defined"); while (ruleIterator.hasNext()) { rule = (Rule) ruleIterator.next(); logger.info("Rule for configuring " + rule.getName()); if (rule.getKpi()!=null) ReservoirDirectory.getInstance() .registerObject(rule.getKpi().getFQN(), rule.getKpi()); System.out.println (rule.getKPIName()); // System.out.println ("Looking for " +new FQN(rule.getKPIName()) + " " +rule.getKpi().getFQN() + " " + rule.getKPIName()); rule.configure((ServiceKPI) ReservoirDirectory.getInstance() .getObject(new FQN(rule.getKPIName()))); // if (rule.getKpi()!=null) // rule.configure(rule.getKpi()); ReservoirDirectory.getInstance() .registerObject(rule.getFQN(), rule); } } /** * Initializes all the structures needed by the FSM to begin the service * lifecycle. * * @param serviceName * Name of the service to be created. */ @SuppressWarnings("unchecked") public void init(String serviceName, String customerName) { logger.info("Initiating FSM for service defined in file " + xmlFile + " , customer " + customerName); Customer client; // Check if customer already present in directory. FQN customerFQN = new Customer(customerName).getFQN(); if (ReservoirDirectory.getInstance().isNameRegistered(customerFQN)) { logger.info("Customer already present: " + customerFQN.toString()); client = (Customer) ReservoirDirectory.getInstance().getObject( customerFQN); } else { logger.info("New customer: " + customerFQN.toString() + ", registering in directory"); client = new Customer(customerName); ReservoirDirectory.getInstance().registerObject(client.getFQN(), client); DbManager.getDbManager().save(client); } try { parser = new Parser(xmlFile, client, serviceName); parser.parse(); } catch (ManiParserException ex) { logger.error( "ManiParserException when trying to parse manifest file " + xmlFile, ex); throw new Error( "ManiParserException when trying to parse manifest file " + xmlFile, ex); } logger.info("Manifest file successfully parsed"); try { sap = parser.getServiceApplication(); client.registerService(sap); registerInDirectory(); // inform its lcc that the service FSM has been created logger .info("Reporting to Lifecycle Controler the FSM has been created for Service Application"); lcc.registerFSM(sap.getFQN(), this); this.lcc.addCustomer(client); rle.configure(this); rle.claudiaRules2Drools(); } catch (Exception e) { e.printStackTrace(); } boolean callSCA = false; if (callSCA) { try { ServiceConfigurationAnalyzer sca = new ServiceConfigurationAnalyzer(); logger.info("Calling Service Config Analyzer, client " + client.getCustomerName()); sap = sca.refineService(sap); } catch (Exception ex) { logger.error( "Exception caught when calling to Service Config Analyzer, message: " + ex.getMessage(), ex); } } else logger.info("Skipping SCA call..."); logger.info ("one rules"); URL oneURL = null; try { String url = "http://"+ SMConfiguration.getInstance() .getVEEMHost()+":"+ SMConfiguration.getInstance().getVEEMPort()+ SMConfiguration.getInstance().getVEEMPath(); logger.info(url); oneURL = new URL("http", SMConfiguration.getInstance() .getVEEMHost(), SMConfiguration.getInstance().getVEEMPort(), SMConfiguration.getInstance().getVEEMPath()); logger.info("VEEM listening on URL " + oneURL); } catch (MalformedURLException ex) { } String urlTCloud = oneURL.toString(); logger.info(" url ? " + SMConfiguration.getInstance().getUrlPlacement()); logger.info(" checking the service "); if (SMConfiguration.getInstance().getUrlPlacement()!=null) { logger.info("Choosing the site to be deployed because of placement decisions"); PlacementModuleClient placement = new PlacementModuleClient (SMConfiguration.getInstance().getUrlPlacement()); try { String url = placement.bestOVFProvider(sap.getXmlFile()); if (url != null) urlTCloud = url; } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } vmi = new TCloudClient(oneURL.toString()); // Initialize the WASUP client. if (SMConfiguration.getInstance().isMonitoringEnabled()) { claudiaMonitoring = new Monitoring (); } // Initialize the lastElasticityInterval Map for (VEE veeItr : sap.getVEEs()) lastElasticityInterval.put(veeItr, new long[2]); if (SMConfiguration.getInstance().isACDActive()) { try { vmi.sendACD(sap); } catch (Throwable t) { logger .error("The ACD could not be sent due to the following exception: " + t.getMessage()); } } DbManager.getDbManager().save(sap); currentState = INIT; nextState = currentState; } public void loadService(ServiceApplication sap) { logger.info("Loading service into the FSM: " + sap.getSerAppName()); this.sap = sap; try { parser = new Parser(sap.getXmlFile(), sap.getCustomer(), sap .getSerAppName()); } catch (ManiParserException ex) { logger.error( "ManiParserException when trying to parse manifest file " + xmlFile, ex); throw new Error( "ManiParserException when trying to parse manifest file " + xmlFile, ex); } parser.setServiceApplication(sap); registerInDirectory(); logger .info("Reporting to Lifecycle Controler the FSM has been created for Service Application"); lcc.registerFSM(sap.getFQN(), this); rle.configure(this); rle.claudiaRules2Drools(); URL oneURL = null; try { oneURL = new URL("http", SMConfiguration.getInstance() .getVEEMHost(), SMConfiguration.getInstance().getVEEMPort(), SMConfiguration.getInstance().getVEEMPath()); logger.info("VEEM listening on URL " + oneURL); } catch (MalformedURLException ex) { } vmi = new TCloudClient(oneURL.toString()); // Initialize the WASUP client. /* if (SMConfiguration.getInstance().isWasupActive()) { try { wasupClient = WasupHierarchy.getWasupHierarchy(); } catch (Exception e) { logger.error("Error login to the WASUP: " + e.getMessage()); } catch (Throwable e) { logger.error("Unknow error connecting to WASUP: " + e.getMessage(), e); } }*/ // Initialize the lastElasticityInterval Map for (VEE veeItr : sap.getVEEs()) lastElasticityInterval.put(veeItr, new long[2]); // Recreate the array with the NICS to be undeployed nicsToDeploy = sap.getNetworks(); veesRollBack.addAll(DbManager.getDbManager().getList(VEEReplica.class)); rle.run(); currentState = RUNNING; nextState = currentState; } /** * Main process of the FSM. The main loop consists of two actions: consuming * an event from the Lifecycle, and transitioning to the next state, using * the information on that event. * * Two conditions finish the execution of the FSM: the abort flag, that is * set if the abort() method is called during the SPECIFIED state, makes the * service finish with an error log; the finishExecution is set when the * Service is done (it has received the undeploy message). * */ public void run() { while (!finishExecution) { currentState = nextState; try { // wait for the arrival of the order to deploy the service Thread.sleep(POLLING_PERIOD); this.interrupt(); if (abort) { logger .error("Service lifecycle execution aborted for service [" + sap.getFQN() + "], due to the following reason: " + abortMessage); break; } } catch (InterruptedException e) { try { // ask whether is there any message nextState = getNextState(lcc.deliver(sap.getFQN()), currentState); } catch (InterruptedException ex) { logger.error("InterruptedException caught ", ex); } catch (MalformedURLException ex) { logger.error("MalformedURLException caught", ex); } } } // Remove the FSM from the Lifecycle controller lcc.deregisterFSM(this.getServiceFQN()); if (finishExecution) logger.info("Service lifecycle finished cleanly"); } public FQN getServiceFQN() { return (sap.getFQN()); } public ServiceApplication getServiceApplication() { return this.sap; } /** * Used to check whether an action should be discarded due to the elasticity * interval. Used to prevent the FSM to execute out of date actions. * * @param vee * VEE that is being the target of the action. There is a * different elasticity interval for each vee. * * @param time * Time when the event was generated. * * @return <i>true</i> if the action can proceed. <i>false</i> if the action * should be discarded. * */ private boolean checkElasticityInterval(VEE vee, long time) { long[] interval = lastElasticityInterval.get(vee); if (interval[0] == 0 || interval[1] == 0) return true; if (time < interval[0] || time > interval[1]) return true; return false; } public boolean startService() { // in this case we use an Array so as to sort it properly int caux =0; veeArray = new VEE[sap.getVEEs().size()]; for (VEE aux: sap.getVEEs()) { for (int g=0; g<sap.getVEEs().size(); g++) { if (aux.getDeploymentOrder()==-1&& caux==g) { System.out.println ("adding to position " + g+ " node " + aux.getVEEName()); veeArray[g] = aux; caux++; continue; } else if (aux.getDeploymentOrder()==g) { System.out.println ("adding to position " + g+ " node " + aux.getVEEName()); veeArray[g] = aux; continue; } } } // rearrange the array according to the order field in the VEE // object // VEE implements Comparable //Arrays.sort(veeArray); // First of all, check the needed networks have been created. if (!checkAndDeployNetworks()) { abort("Network creation error"); return false; } // for each VEE, get the required replicas for (int j = 0; j < veeArray.length; j++) { logger.info("Deployment step " + (j + 1) + ", VEE: " + veeArray[j].getVEEName() + " with " + veeArray[j].getInitReplicas() + " replicas"); // get the required number of replicas. Set<VEEReplica> replicas = createReplica(veeArray[j], veeArray[j].getInitReplicas()); if (replicas == null) { abort("Replicas could not be created for vee [" + veeArray[j].getFQN() + "]"); return false; } PaasUtils paas = new PaasUtils(); /*for (VEEReplica rep: replicas) { ddd String replicaxml = paas.getVEE(rep); HashMap ips = paas.getVeePaaSSetIpFromXML (replicaxml); Iterator it = ips.entrySet().iterator(); while (it.hasNext()) { Map.Entry e = (Map.Entry)it.next(); System.out.println(e.getKey() + " " + e.getValue()); for (NIC nic: rep.getNICs()) { if (e.getKey().equals(nic.getNICConf().getNetwork().getName())) { System.out.println ("Adding IP " + e.getValue() + " from network " + e.getKey() + " for replica " + rep.getVEE().getVEEName()+rep.getId()); nic.addIPAddress((String)e.getValue()); } } } }*/ if (SMConfiguration.getInstance().isPaaSAware()) { logger.info ("Calling REC Manager for installing softwaer in the VM"); RECManagerClient rec = new RECManagerClient(SMConfiguration.getInstance().getSdcUrl()); try { rec.installProductsInService (veeArray[j]); } catch (AccessDeniedException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } catch (CommunicationErrorException e1) { // TODO Auto-generated catch block logger.error("Error to install the product " + e1.getMessage()); abortServiceAlreadyDeployed("Error to install the product " + e1.getMessage()+ ". Replicas could not be created for vee [" + veeArray[j].getFQN() + "]"); return false; } for (VEEReplica replica: replicas) { if (paas.isPaaSAware(veeArray[j])) { // if it is paas aware, we have to install the software..... String xml = paas.getVEE(replica); String ip = paas.getVeePaaSIpFromXML (xml); logger.info("IP for "+ veeArray[j].getVEEName() + " " + ip); String [] result = paas.getVeePaaSUserNamePaaswordFromXML(xml); System.out.println ("username " + result[0] + " pass " + result[1]); // veeArray[j].setUserName(result[0]); // veeArray[j].setPassword(result[1]); logger.info ("Configuring VM " + veeArray[j].getVEEName()+ " with the right parameters"); try { rec.installProductsInVm (veeArray[j], ip, result[0], result[1]); } catch (Exception e1) { // TODO Auto-generated catch block logger.error("Error to install the product " + e1.getMessage()); abortServiceAlreadyDeployed("Error to install the product " + e1.getMessage()+ ". Error to configure the VM]"); return false; } for (Product product: veeArray[j].getProducts()) { logger.info ("Installing software " + product.getName()); try { paas.installProduct(SMConfiguration.getInstance().getSdcUrl(),product, ip); } catch (Exception e) { // TODO Auto-generated catch block logger.error("Error to install the product " + e.getMessage()); abortServiceAlreadyDeployed("Error to install the product " + e.getMessage()+ ". Replicas could not be created for vee [" + veeArray[j].getFQN() + "]"); return false; } } } } } } rle.run(); logger.info("DONE with ALL replicas and ALL VEEs "); // Oundence all the VEES are working, it's time to replicate its structure // in // MONITORING if (SMConfiguration.getInstance().isMonitoringEnabled() && !claudiaMonitoring.setupMonitoring(sap)) { logger.error("Problems to set up monitoring "); } return true; } private void reportKPIValue () { } public boolean elasticityCreateReplica(String veeType, int replicaNumber, long initialTime, boolean checkinterval) { VEE vee2Replicate = (VEE) ReservoirDirectory.getInstance().getObject( new FQN(veeType)); if (!checkElasticityInterval(vee2Replicate, initialTime) && checkinterval==true) { logger.warn("Action discarded due to the Elasticity Interval."); return false; } // Save the beginning of the interval lastElasticityInterval.get(vee2Replicate)[0] = initialTime - ELASTICITY_MARGIN; // check that the current number of replicas does not // exceed the maximum int currentReplicas = vee2Replicate.getCurrentReplicas(); if (currentReplicas < vee2Replicate.getMaxReplicas()) { if (createReplica(vee2Replicate, replicaNumber) == null) logger.error("Replica could not be created."); else logger.info("Replica created successfully"); } else { logger .warn("Replica was not created, for the VEE already have the maximum number of replicas"); } // Save the ending part of the interval lastElasticityInterval.get(vee2Replicate)[1] = System .currentTimeMillis() + ELASTICITY_MARGIN; return true; } public boolean elasticityRemoveReplica(String veeType, long initialTime, boolean checkinterval) { VEE vee2Plicate = (VEE) ReservoirDirectory.getInstance().getObject( new FQN(veeType)); if (!checkElasticityInterval(vee2Plicate, initialTime) && checkinterval==true) { logger.warn("Action discarded due to the Elasticity Interval."); return false; } // Save the beginning of the interval lastElasticityInterval.get(vee2Plicate)[0] = initialTime - ELASTICITY_MARGIN; // check that the current number of replicas is not going to be // under the minimum if (vee2Plicate.getCurrentReplicas() > vee2Plicate.getMinReplicas()) { Set<VEEReplica> replicas = vee2Plicate.getVEEReplicas(); // assume all the replicas can equally be removed /* int maxreplica = 0; Set<VEEReplica> plicateSet = new HashSet<VEEReplica>(); VEEReplica removeCandidate = null; for (Iterator<VEEReplica> removeIt = replicas.iterator(); removeIt .hasNext();) { VEEReplica plicate = (VEEReplica) removeIt.next(); if ((plicate.getId()) > maxreplica) { maxreplica = plicate.getId(); removeCandidate = plicate; } }*/ Set<VEEReplica> plicateSet = getReplicaCandiates (replicas); if (plicateSet == null) { logger.error("No replicas to delete "); return true; } for (VEEReplica removeCandidate: plicateSet) { Set<VEEReplica> aux = new HashSet<VEEReplica>(); aux.add(removeCandidate); // invoke the appropriate VMI methods if (shutdown(aux)) { // Remove it from wasup /* if (SMConfiguration.getInstance().isWasupActive()) { try { wasupClient.removeNode(removeCandidate); } catch (IOException e) { logger .error("The replica could not be removed from WASUP: " + e.getMessage()); } catch (Throwable e) { logger.error( "Unknow error connecting to WASUP: " + e.getMessage(), e); } }*/ // Parche para borrar la replica del reservoir directory FQN fqn = removeCandidate.getFQN(); ReservoirDirectory.getInstance().removeMatchingNames(fqn); // update the data model by removing a new // replica and increasing the number of // current replicas //vee2Plicate.getVEEReplicas().remove(plicate); vee2Plicate.unregisterVEEReplica(removeCandidate); vee2Plicate.removeCurrentReplicas(); veesRollBack.remove(removeCandidate); if (vee2Plicate.isVEEReplicaRegistered(removeCandidate)){ logger.error("The replIca HAS NOT BEEN REMOVED"); } logger.info("" +"AFTER SCALING DOWN THERE ARE " + vee2Plicate.getCurrentReplicas()); return true; } else { logger.error("FAILURE WHILE REMOVING THE REPLICA!!!!!!"); } } // Save the ending part of the interval lastElasticityInterval.get(vee2Plicate)[1] = System.currentTimeMillis() + ELASTICITY_MARGIN; } return false; } private Set<VEEReplica> getReplicaCandiates(Set<VEEReplica> replicas) { for (VEEReplica replica : replicas) { VEE balancerVEE = replica.getVEE().getBalancedBy(); logger.info("Is a replica balanced por" + replica.getVEE().getBalancedBy()); if (balancerVEE!= null) { return getReplicaCandiatesLastElement (replicas); // return getReplicaCandiatesLoadBalancer ( replicas); } else return getReplicaCandiatesLastElement (replicas); } return null; } private Set<VEEReplica> getReplicaCandiatesLastElement (Set<VEEReplica> replicas) { logger.info("Last element"); // assume all the replicas can equally be removed int maxreplica = 0; Set<VEEReplica> plicateSet = new HashSet<VEEReplica>(); VEEReplica removeCandidate = null; for (Iterator<VEEReplica> removeIt = replicas.iterator(); removeIt .hasNext();) { VEEReplica plicate = (VEEReplica) removeIt.next(); if ((plicate.getId()) > maxreplica) { maxreplica = plicate.getId(); removeCandidate = plicate; } } plicateSet.add(removeCandidate); return plicateSet; } private Set<VEEReplica> getReplicaCandiatesLoadBalancer (Set<VEEReplica> replicas) { logger.info("Obtain replicas to delete from balancer"); if (replicas.size()==0) return null; Set<VEEReplica> plicateSet = new HashSet<VEEReplica>(); VEE balancerVEE = null; String ipbalancer = null; for (VEEReplica balancer : replicas) { balancerVEE = balancer.getVEE().getBalancedBy(); for (VEEReplica veebalancer: balancerVEE.getVEEReplicas()) { for (NIC nic : veebalancer.getNICs() ) { if (!nic.getNICConf().getNetwork().getPrivateNet()) ipbalancer = nic.getIPAddresses().get(0); } } /* for (NIC nic : veeReplica.getNICs()) { /* if (balancerVEE!=null) { for (NIC nic: balancerVEE.get) } veeReplica.getNICs() veeReplica.getNICs() balancerVEE.get for (NICConf nic : balancerVEE.getNICsConf()) { if (!nic.getNetwork().getPrivateNet()) { String[] addresses = nic.getNetwork().getNetworkAddresses(); ipbalancer = nic.addIPAddress } }*/ } String[] ipreplica = null; try { logger.info("IP balancer " + ipbalancer+ " " + balancerVEE .getLbManagementPort()); ipreplica = this.lbConfigurator.getNodeRemove(ipbalancer, balancerVEE .getLbManagementPort(), 1); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); return null; } if (ipreplica==null) { logger.error("No node obtained to be removed " ); return null; } for (int i=0; i<ipreplica.length; i++) { System.out.println (ipreplica[i]); VEEReplica replica = getReplicaByIp (replicas, ipreplica[i] ); if (replica== null) { logger.error("No replica for IP " + ipreplica[i]); continue; } plicateSet.add(replica); } return plicateSet; } private VEEReplica getReplicaByIp (Set<VEEReplica> replicas, String Ip) { for (VEEReplica replica : replicas) { for (NIC nic : replica.getNICs()) { if (!nic.getNICConf().getNetwork().getPrivateNet()) { logger.info("Looking for ip " + Ip + " ip found " + nic.getIPAddresses().get(0)); if (nic.getIPAddresses().get(0).equals(Ip)) { return replica; } } } } return null; } private int dispatchEvent(SMControlEvent cntrlEvent) throws MalformedURLException { int retorno = 0; // Check there is really an event. if (cntrlEvent == null) return currentState; // Check the event is acceptable in the actual state boolean accepted = false; for (Integer eventId : stateEventMatrix.get(currentState)) if (cntrlEvent.getControlEventType() == eventId) accepted = true; if (!accepted) { logger.error("Event discarded: not acceptable in this state."); return currentState; } if (!cntrlEvent.getServiceFQN().equals(sap.getFQN().toString())) { logger .error("¡The FQNs of service and event doesn't match.\nService FQN: " + sap.getFQN().toString() + "\nEvent FQN: " + cntrlEvent.getServiceFQN()); } logger.info("\n\n* Dispatching event of type: " + cntrlEvent.getControlEventType()); switch (cntrlEvent.getControlEventType()) { case SMControlEvent.ELASTICITY_RULE_VIOLATION: logger .info("\n* FSM Processing Control Event: ELASTICITY_RULE_VIOLATION\n"); // this method is triggered by the RuleEngine on the // LifecycleController. Get rule action and execute it String action = cntrlEvent.getSuggestedAction(); logger.info(SMControlEvent.ELASTICITY_RULE_VIOLATION + ", action: " + action); // check the action grammar and perform the needed VMI // actions if (action.contains("createReplica")) { int scaleUpNumber = getCreateReplicaInfo(action); // By default always checkinterval boolean checkinterval = true; boolean reply = true; for (int scaleup = 0; scaleup < scaleUpNumber; scaleup++) { // get the action parameters int initIndex = action.indexOf("("); int endIndex = action.lastIndexOf(")"); String veeType = action.substring(initIndex + 1, endIndex); String[] parameters = veeType.split(","); // set to true the elasticity checkinterval return reply = true; // only check interval for the first replica of a group in case of multiple scaling up if (scaleup > 0) checkinterval = false; else checkinterval = true; if (parameters.length < 2) { reply = elasticityCreateReplica(parameters[0], 1, cntrlEvent .getInitialTime(),checkinterval); } else { reply = elasticityCreateReplica(parameters[0], Integer .parseInt(parameters[1]), cntrlEvent .getInitialTime(),checkinterval); } // in case of chack interval reply false, don't increase the scaleup variable and try again if ((reply==false) && (scaleup > 0)) { scaleup--; } } retorno = FSM.RUNNING; logger.info("FSM RUNNING"); } else if (action.contains("removeReplica")) { int scaleDownNumber = getRemoveReplicaInfo(action); // By default always checkinterval boolean checkinterval = true; boolean reply = true; for (int scaledown = 0; scaledown < scaleDownNumber; scaledown++) { // get the action parameters int initIndex = action.indexOf("("); int endIndex = action.lastIndexOf(")"); String veeType = action.substring(initIndex + 1, endIndex); // set to true the elasticity checkinterval return reply = true; // only check interval for the first replica of a group in case of multiple scaling up if (scaledown > 0) checkinterval = false; else checkinterval = true; reply = elasticityRemoveReplica(veeType, cntrlEvent.getInitialTime(),checkinterval); // in case of chackinterval reply false, don't increase the scaledown variable and try again if ((reply==false) && (scaledown > 0)) { scaledown--; } //Check if there's more replicas to remove if (((scaledown+1) < scaleDownNumber) && reply==true){ //Lazy Scale down, wait for the next replica to be removed try { logger.info("Lazy Scale Down: waiting " + lazyScaleDownTime +" seconds to remove next replica"); Thread.sleep(lazyScaleDownTime*1000); } catch(InterruptedException e) { e.printStackTrace(); } } } retorno = FSM.RUNNING; logger.info("FSM RUNNING"); } else { // or return an error if they weren't retorno = FSM.ERROR; } break; case SMControlEvent.NEW_RULE_ADDED: logger.info("\n* FSM Processing Control Event: NEW_RULE_ADDED\n"); rle.addRule(cntrlEvent.getSuggestedAction()); retorno = FSM.RECONFIGURED; break; case SMControlEvent.RULE_CHANGED: logger.info("\n* FSM Processing Control Event: RULE_CHANGED\n"); retorno = FSM.RECONFIGURED; break; case SMControlEvent.UNDEPLOY_SERVICE: logger.info("\n* FSM Processing Control Event: UNDEPLOY_SERVICE\n"); // issue the appropriate VMI Events to undeploy the service, shutdown(veesRollBack); if (nicsToDeploy==null) nicsToDeploy =new HashSet<Network>(); removeNetworks(); sap.getCustomer().unregisterService(sap); DbManager.getDbManager().save(sap.getCustomer()); FQN fqnService = sap.getFQN(); DbManager.getDbManager().remove(sap); DbManager.getDbManager().remove(fqnService); retorno = FSM.FINISHED; if (SMConfiguration.getInstance().isMonitoringEnabled() && !claudiaMonitoring.deletingMonitoring(sap)) { logger.error("Problems deleting monitoring "); } break; case SMControlEvent.START_SERVICE: if (startService()) { retorno = FSM.RUNNING; if (SMConfiguration.getInstance().getReportingKpiEnable()) { System.out.println ("Enabliong KPIs reporting"); new Thread ( new ReportKPIValue(sap)).start(); } System.out.println ("Con estado running "); } else retorno = FSM.ERROR; break; default: retorno = FSM.ERROR; break; } System.out.println ("Devolviendo running "); return retorno; } private void removeNetworks() { try { vmi.deleteNetwork(nicsToDeploy); } catch (AccessDeniedException e) { logger.error("Access denied accessing the VMI: " + e.getMessage()); } catch (CommunicationErrorException e) { logger .error("Couldn't connect to the VMI to undeploy the networks: " + e.getMessage()); } } /** * Analyzes the event in the queue to determine the next state in the FSM * * @param cntrlEvent * @param currentState */ private int getNextState(SMControlEvent cntrlEvent, int currentState) throws InterruptedException, MalformedURLException { int retorno = currentState; switch (currentState) { case INIT: logger.info("\n\n\n\n* Processing State: INIT"); retorno = dispatchEvent(cntrlEvent); break; case RUNNING: if (!(cntrlEvent == null)) { retorno = dispatchEvent(cntrlEvent); } break; case RECONFIGURED: logger.info("\n\n\n\n* Processing State: RECONFIGURED"); retorno = FSM.RUNNING; break; case FINISHED: try { finishExecution = true; } catch (Throwable ex) { } break; case ERROR: logger.info("\n\n\n\n* Processing State: ERROR"); shutdown(veesRollBack); retorno = FSM.FINISHED; break; } if (abort) retorno = FSM.ERROR; return (retorno); } /** * Read the SA configuration to find out the FQN of the required networks. * Calculate its required size, deploy them and save a reference in the FSM * network repository. * * The size is calculated after the sum of the maximum number of replicas * for each VEE using the network. * * @throws CommunicationErrorException * @throws AccessDeniedException * */ private int getCreateReplicaInfo(String action){ int scaleUpNumber; // Decide how many replicas can be created with the percentage property int initIndexTemp = action.indexOf("("); int endIndexTemp = action.lastIndexOf(")"); String veeTypeTemp = action.substring(initIndexTemp + 1, endIndexTemp); String[] parametersTemp = veeTypeTemp.split(","); VEE vee2ReplicateTemp = (VEE) ReservoirDirectory.getInstance().getObject( new FQN(parametersTemp[0])); try { int currentReplicasTemp = vee2ReplicateTemp.getCurrentReplicas(); logger.info("Current number of replicas:" + currentReplicasTemp); logger.info("Scale Up Percentage:" + scaleUpPercentage); scaleUpNumber = Math.round((scaleUpPercentage/100)*currentReplicasTemp); } catch (NullPointerException npe) { logger.error("problem getting number of replicas"); scaleUpNumber = 1; } //Always scale 1 at minimum if (scaleUpNumber < 1) { scaleUpNumber = 1; } logger.info("Scaling up " + scaleUpNumber +" more replicas if possible"); return scaleUpNumber; } private int getRemoveReplicaInfo(String action){ int scaleDownNumber; // Decide how many replicas can be removed with the percentage property int initIndexTemp = action.indexOf("("); int endIndexTemp = action.lastIndexOf(")"); String veeTypeTemp = action.substring(initIndexTemp + 1, endIndexTemp); String[] parametersTemp = veeTypeTemp.split(","); VEE vee2PlicateTemp = (VEE) ReservoirDirectory.getInstance().getObject( new FQN(veeTypeTemp)); try { int currentReplicasTemp = vee2PlicateTemp.getCurrentReplicas(); logger.info("Current number of replicas:" + currentReplicasTemp); logger.info("Scale Down Percentage:" + scaleDownPercentage); scaleDownNumber = Math.round((scaleDownPercentage/100)*currentReplicasTemp); } catch (NullPointerException npe) { logger.error("problem getting number of replicas"); scaleDownNumber = 1; } //Always scale 1 at minimum if (scaleDownNumber < 1) { scaleDownNumber = 1; } logger.info("Scaling Down " + scaleDownNumber +" more replicas if possible"); return scaleDownNumber; } private boolean checkAndDeployNetworks() { logger.info("Checking and deploying networks"); nicsToDeploy = new HashSet<Network>(); if (SMConfiguration.getInstance().getIpManagement()) { // Calculate network sizes Map<Network, Integer> networkMaximumSizes = new HashMap<Network, Integer>(); for (VEE vee : sap.getVEEs()) { HashMap<String, Integer> ipsNeeded = parser .getNumberOfIpsPerNetwork(vee.getFQN().contexts()[vee .getFQN().contexts().length - 1]); for (NICConf nic : vee.getNICsConf()) { Integer numberOfIps = ipsNeeded.get(nic.getNetwork().getName()); if (numberOfIps == null || numberOfIps == 0) numberOfIps = 1; logger.info(numberOfIps + "(" + vee.getMaxReplicas() * numberOfIps + ")" + " IPs required for vee " + vee.getVEEName() + " on network " + nic.getNetwork().getName()); if (networkMaximumSizes.containsKey(nic.getNetwork())) { networkMaximumSizes.put(nic.getNetwork(), networkMaximumSizes.get(nic.getNetwork()) + vee.getMaxReplicas() * numberOfIps); } else { networkMaximumSizes.put(nic.getNetwork(), vee .getMaxReplicas()); } } } for (Network net : networkMaximumSizes.keySet()) { // Update the network size, based on the minumum number of bits // needed to represent the size net.setSize(networkMaximumSizes.get(net)); if (net.getSize() > 1) net.setSize(net.getSize() + 2); logger.info("Asking for a " + ((net.getPrivateNet()) ? "private" : "public") + " network with " + net.getSize() + " IPs"); String[] address = lcc.getNetworkAddress(net.getSize(), !net .getPrivateNet()); if (address == null) { logger .error("The lifecycle manager was unable to give enough IPs. It's impossible to deploy all the needed networks. Aborting."); return false; } net.setNetworkAddresses(address); nicsToDeploy.add(net); } } else { for (VEE vee : sap.getVEEs()) { for (NICConf nic : vee.getNICsConf()) { nicsToDeploy.add(nic.getNetwork()); } } } try { vmi.allocateNetwork(nicsToDeploy); return true; } catch (AccessDeniedException e) { logger.error("Access denied when allocating a new network: " + e.getMessage() + ". Aborting."); } catch (CommunicationErrorException e) { logger.error("Communication error when allocating a new network: " + e.getMessage() + ". Aborting."); } catch (NotEnoughResourcesException e) { // TODO Auto-generated catch block e.printStackTrace(); } logger.info("Networks for Service Application " + sap.getFQN().toString() + " checked and deployed"); return false; } /** * Method to shutdown a set of running replicas * * @param rollBack * * @return */ private boolean shutdown(Set<VEEReplica> rollBack) { Map<VEEReplica, VEEReplicaUpdateResult> updateResults = null; try { updateResults = vmi.shutdownReplica(rollBack); } catch (CommunicationErrorException ex) { logger.error("Comunication error waiting for Replica shutdown: " + ex.getMessage()); return false; } catch (AccessDeniedException e) { logger.error("Access error waiting for Replica shutdown: " + e.getMessage()); return false; } Iterator<VEEReplica> rollIt = rollBack.iterator(); while (rollIt.hasNext()) { VEEReplica veeReplica = rollIt.next(); logger.info("Shutting down replic: " + veeReplica.getFQN()); // Shutdown the replica VEEReplicaUpdateResult updateResult = updateResults.get(veeReplica); if (!updateResult.isSuccess()) { logger.error("Update failed: " + updateResult.getMessage()); return false; } // If replica is loadbalanced, balancer should be notified VEE balancerVEE = veeReplica.getVEE().getBalancedBy(); if (balancerVEE!= null) removeReplicaFromLoadBalancer(veeReplica, balancerVEE); // Release the ip addres leased to the replica. for (NIC nic : veeReplica.getNICs()) for (String ipAddress : nic.getIPAddresses()) if (nic.getNICConf().getNetwork().getNetworkAddresses()!=null) lcc.releaseHostAddress(ipAddress, nic.getNICConf() .getNetwork().getNetworkAddresses()[0]); // Once the replica is finished, it should be removed from the // storage system. // But first, it has to be unlinked from the VEE if (veeReplica.getVEE().isVEEReplicaRegistered(veeReplica)) { veeReplica.getVEE().unregisterVEEReplica(veeReplica); } /* List<VEEReplica> sas = DbManager.getDbManager().getList (VEEReplica.class); System.out.println ("ANTES"); for (VEEReplica s: sas) { System.out.println (s.getFQN()); }*/ FQN fqnReplica = veeReplica.getFQN(); DbManager.getDbManager().remove(veeReplica); DbManager.getDbManager().remove(fqnReplica); DbManager.getDbManager().save(veeReplica.getVEE()); /* sas = DbManager.getDbManager().getList (VEEReplica.class); System.out.println ("DESPUES"); for (VEEReplica s: sas) { System.out.println (s.getFQN()); }*/ } return true; } /** * Method to deploy a replica into the underlying infrastructure * * @param veeReplica * @return */ private boolean deployReplica(Set<VEEReplica> veeReplicasConfs) { Map<VEEReplica, VEEReplicaAllocationResult> allocResults = null; try { allocResults = vmi.allocateVEEReplicas(veeReplicasConfs, SubmissionModelType.BESTEFFORT); } catch (NotEnoughResourcesException ex) { abort("NotEnoughResourcesException exception caught " + ex.getMessage()); return false; } catch (AccessDeniedException ex) { abort("AccessDeniedException exception caught " + ex.getMessage()); return false; } catch (VEEReplicaDescriptionMalformedException ex) { abort("VEEReplicaDescriptionMalformedException exception caught " + ex.getMessage()); return false; } catch (CommunicationErrorException ex) { abort("CommunicationErrorException exception caught " + ex.getMessage()); return false; } for (VEEReplica veeReplica: veeReplicasConfs) { logger.info("**** Reviewing replica " + veeReplica.getFQN()); VEEReplicaAllocationResult allocResult = allocResults.get(veeReplica); if (!allocResult.isSuccess()) { abort("VIM reports error: "+ allocResult.getMessage()); return false; } if (!SMConfiguration.getInstance().getIpManagement()) getUpdateIpsReplica (veeReplica); // If replica is loadbalanced, balancer should be notified VEE balancerVEE = veeReplica.getVEE().getBalancedBy(); if (balancerVEE!=null){ logger.info("Adding replica to LB"); addReplicaToLoadBalancer(veeReplica, balancerVEE); } else { logger.info(veeReplica.getFQN() + " is not balanced"); } } // The allocation was successful and the replica is UP and Running // update the rollback veesRollBack.addAll(veeReplicasConfs); return true; } private void getUpdateIpsReplica (VEEReplica rep) { // Obtain the IP and update PaasUtils paas = new PaasUtils(); String replicaxml = paas.getVEE(rep); if (replicaxml == null) { logger.error("It is not possible to obtain the replica Id"); return; } HashMap ips = paas.getVeePaaSSetIpFromXML (replicaxml); Iterator it = ips.entrySet().iterator(); while (it.hasNext()) { Map.Entry e = (Map.Entry)it.next(); logger.info ("network name " + e.getKey() + " " + e.getValue()); for (NIC nic: rep.getNICs()) { logger.info (" for networking ... " + e.getKey()+ " "+ nic.getNICConf().getNetwork().getName()); if (e.getKey().equals(nic.getNICConf().getNetwork().getName()) || (((String)e.getKey()).endsWith(nic.getNICConf().getNetwork().getName()) ==true)) { logger.info ("Adding IP " + e.getValue() + " from network " + e.getKey() + " for replica " + rep.getVEE().getVEEName()+ " " + rep.getId()); nic.addIPAddress((String)e.getValue()); } } } } /** * @param veeReplica * @param balancerVEE */ private void addReplicaToLoadBalancer(VEEReplica veeReplica, VEE balancerVEE) { addRegularReplicaToBalancer(veeReplica, balancerVEE); } /** * Creates a customization image for the VEEReplica passed as a parameter, * containing only one file, called ovf-env.xml, with all the customization * data needed to initialize the Replica. * * Returns an URL to access the replica. * * @param veeReplica * @param createISOImage * @return */ private String createCustomizationFile(VEEReplica veeReplica) { String customizationDirName = customImagesDir + "/" + veeReplica.getFQN().toString(); File customizationDir = new File(customizationDirName); customizationDir.mkdirs(); String customizationFileName = customizationDirName + "/ovf-env.xml"; File customizationFile = new File(customizationFileName); logger.info("Creating customization file in " + customizationFile.getPath()); String customizationDirURLPath = SMConfiguration.getInstance() .getImagesServerPath() + "/" + veeReplica.getFQN().toString(); PrintWriter out = null; try { out = new PrintWriter(new FileWriter(customizationFile)); } catch (IOException ex) { java.util.logging.Logger.getLogger(FSM.class.getName()).log( java.util.logging.Level.SEVERE, null, ex); return ex.getMessage(); } out.write(veeReplica.getOVFEnvironment() + "\n"); out.close(); String urlToCustomFile = protocol + SMConfiguration.getInstance().getImagesServerHost() + ":" + SMConfiguration.getInstance().getImagesServerPort() + customizationDirURLPath + "/ovf-env.xml"; logger.info("URL to customization file: " + urlToCustomFile); return urlToCustomFile; } /** * Returns the number of replicas for the indicated VEE FQN, if the FQN * belongs to this service. * * @param veeFqn * FQN of the VEE whose replica number want to be retrieved. * * @return The actual number of replicas if the VEE is part of the current * service or 0 otherwise. */ public int getAmount(String veeFqn) { VEE vee = (VEE) ReservoirDirectory.getInstance().getObject( new FQN(veeFqn)); if (vee != null) { logger.info("VEE " + vee + " current replicas: " + vee.getCurrentReplicas()); return vee.getCurrentReplicas(); } logger.error("Not VEE registered with FQN " + veeFqn); return 0; } /** * Abort the current action if the service was deployed successfully or * abort the whole execution of the service if the abort signal is generated * during the SPECIFIED state. * * @param reason * Textual reason to send the abort signal. It will end up in the * logs. */ private void abort(String reason) { if (currentState == INIT) { logger.error("Aborting the FSM due to the following reason: " + reason); abort = true; this.abortMessage = reason; } else { logger.error("Action discarded due to the following reason: " + reason); } } private void abortServiceAlreadyDeployed (String reason) { if (currentState == INIT) { logger.error("Aborting the FSM due to the following reason: " + reason); abort = true; this.abortMessage = reason; } else { logger.error("Action discarded due to the following reason: " + reason); } /* shutdown(veesRollBack); if (nicsToDeploy == null) nicsToDeploy = new HashSet<Network>(); removeNetworks(); sap.getCustomer().unregisterService(sap); DbManager.getDbManager().save(sap.getCustomer()); FQN fqnService = sap.getFQN(); DbManager.getDbManager().remove(sap); DbManager.getDbManager().remove(fqnService);*/ } @SuppressWarnings("unchecked") private Set<VEEReplica> createReplica(VEE originalVEE, int replicaNumber) { /* * Set<VEEReplica> replicas = new HashSet<VEEReplica>(); * * for (int q=0; q < replicaNumber;q++) { * * VEEReplica veeReplica = new VEEReplica(originalVEE); * * replicaCustomInfo = new HashMap<String, String>(); * * logger.info("Deploying replica: "+ veeReplica.getFQN()); * veeReplica.registerHwElementsInResDir(); * * ReservoirDirectory.getInstance().registerObject(veeReplica.getFQN(), * veeReplica); * * MonitoringRestBusConnector restBusConnector = * MonitoringRestBusConnector.getInstance(); List<String> restEndPoints * = restBusConnector.getRestEndPoints(); * * if ((restEndPoints != null) && (restEndPoints.size() > 0)) { * logger.info("KPIMonitorEndPoint customization value: " + * restBusConnector.getRestEndPoints().get(0)); * replicaCustomInfo.put("KPIMonitorEndPoint", * restBusConnector.getRestEndPoints().get(0)); } * * replicaCustomInfo.put("KPIQualifier", sap.getFQN().toString() + * ".kpis"); replicaCustomInfo.put("ReplicaName", * veeReplica.getFQN().toString()); replicaCustomInfo.put("VEEid", * String .valueOf(veeReplica.getId())); * replicaCustomInfo.put("ReplicaName", veeReplica.getFQN().toString()); * * // call parser to complete the hashTable and update the // * CustomizationInformation String in the VEEReplica // object * logger.info("Customizing replica " + veeReplica.getId() + " del VEE " * + originalVEE.getVEEName()); if (replicaCustomInfo.isEmpty()) * logger.info("Empty custom information"); else { Iterator keyIter = * replicaCustomInfo.keySet().iterator(); * * while (keyIter.hasNext()) { String key = (String) keyIter.next(); * logger.info("Key: " + key + "; Value: "+ replicaCustomInfo.get(key)); * } } * * // Get the networks for the VM Environment HashMap<String,String> * masks = new HashMap<String,String>(); * HashMap<String,ArrayList<String>> ips = new * HashMap<String,ArrayList<String>>(); HashMap<String,String> dnss = * new HashMap<String, String> (); HashMap<String,String> gateways = new * HashMap<String, String> (); * * HashMap<String, Integer> ipsNeeded = * parser.getNumberOfIpsPerNetwork(originalVEE.getVEEName()); * * for (Network net: sap.getNetworks()) { masks.put(net.getName(), * net.getNetworkAddresses()[1]); dnss.put(net.getName(), * net.getNetworkAddresses()[2]); gateways.put(net.getName(), * net.getNetworkAddresses()[3]); } * * for (NIC nic: veeReplica.getNICs()) { String networkName = * nic.getNICConf().getNetwork().getName(); * * if (ips.get(networkName)==null) ips.put(networkName, new * ArrayList<String>()); * * Integer iterations = ipsNeeded.get(networkName); * * if (iterations == null || iterations == 0) iterations = 1; * * for (int i=0; i < iterations; i++) { String replicaIP = * lcc.getHostAddress * (nic.getNICConf().getNetwork().getNetworkAddresses()[0]); * * if (replicaIP==null) { abort("Lack of ip addresses"); return null; } * * // Put the IP in the entrypoint map for this network. Map<String, * String> entryPoint = nic.getNICConf().getNetwork().getEntryPoints(); * * if (entryPoint.containsKey(originalVEE.getVEEName())) { String * ipList= entryPoint.get(originalVEE.getVEEName()); * entryPoint.put(originalVEE.getVEEName(), ipList + " " + replicaIP); } * else { entryPoint.put(originalVEE.getVEEName(), replicaIP); } * * nic.addIPAddress(replicaIP); * * ips.get(networkName).add(replicaIP); } } */ if (this.abort) { this.logger .error("Unable to deploy replicas. Service already aborted"); return null; } Set<VEEReplica> replicas = new HashSet<VEEReplica>(); for (int q = 0; q < replicaNumber; q++) { VEEReplica veeReplica = new VEEReplica(originalVEE); replicaCustomInfo = new HashMap<String, String>(); logger.info("Deploying replica: " + veeReplica.getFQN()); veeReplica.registerHwElementsInResDir(); ReservoirDirectory.getInstance().registerObject( veeReplica.getFQN(), veeReplica); ReservoirDirectory.getInstance().registerObject( veeReplica.getMemory().getFQN(), veeReplica.getMemory()); logger.info("PONG Memory FQN: " + veeReplica.getMemory()); Iterator iter = veeReplica.getDisks().iterator(); while (iter.hasNext()) { Disk disc = (Disk) iter.next(); ReservoirDirectory.getInstance().registerObject(disc.getFQN(), disc); logger.info("PONG DISK FQN: " + disc.getFQN()); } iter = veeReplica.getCPUs().iterator(); while (iter.hasNext()) { CPU cpu = (CPU) iter.next(); ReservoirDirectory.getInstance().registerObject(cpu.getFQN(), cpu); logger.info("PONG CPU FQN: " + cpu.getFQN()); } iter = veeReplica.getNICs().iterator(); while (iter.hasNext()) { NIC nic = (NIC) iter.next(); ReservoirDirectory.getInstance().registerObject(nic.getFQN(), nic); logger.info("PONG NIC FQN: " + nic.getFQN() + " for " + nic.getNICConf().getNetwork().getName()); } MonitoringRestBusConnector restBusConnector = MonitoringRestBusConnector .getInstance(); List<String> restEndPoints = restBusConnector.getRestEndPoints(); if ((restEndPoints != null) && (restEndPoints.size() > 0)) { logger.info("KPIMonitorEndPoint customization value: " + restBusConnector.getRestEndPoints().get(0)); replicaCustomInfo.put("KPIMonitorEndPoint", restBusConnector .getRestEndPoints().get(0)); } replicaCustomInfo.put("KPIQualifier", sap.getFQN().toString() + ".kpis"); replicaCustomInfo .put("ReplicaName", veeReplica.getFQN().toString()); replicaCustomInfo.put("VEEid", String.valueOf(veeReplica.getId())); replicaCustomInfo .put("ReplicaName", veeReplica.getFQN().toString()); // call parser to complete the hashTable and update the // CustomizationInformation String in the VEEReplica // object logger.info("Customizing replica " + veeReplica.getId() + " del VEE " + originalVEE.getVEEName()); if (replicaCustomInfo.isEmpty()) logger.info("Empty custom information"); else { Iterator keyIter = replicaCustomInfo.keySet().iterator(); while (keyIter.hasNext()) { String key = (String) keyIter.next(); logger.info("Key: " + key + "; Value: " + replicaCustomInfo.get(key)); } } // Get the networks for the VM Environment HashMap<String, String> masks = new HashMap<String, String>(); HashMap<String, ArrayList<String>> ips = new HashMap<String, ArrayList<String>>(); HashMap<String, String> dnss = new HashMap<String, String>(); HashMap<String, String> gateways = new HashMap<String, String>(); HashMap<String, Integer> ipsNeeded = parser .getNumberOfIpsPerNetwork(originalVEE.getVEEName()); for (Network net : sap.getNetworks()) { if (net.getNetworkAddresses()!=null && net.getNetworkAddresses()[1]!=null) masks.put(net.getName(), net.getNetworkAddresses()[1]); if (net.getNetworkAddresses()!=null &&net.getNetworkAddresses().length>2) dnss.put(net.getName(), net.getNetworkAddresses()[2]); if (net.getNetworkAddresses()!=null &&net.getNetworkAddresses().length>3) gateways.put(net.getName(), net.getNetworkAddresses()[3]); } String staticIpProp = parser.getStaticIpProperty(originalVEE.getVEEName()); logger.info("STatic IP property " +staticIpProp ); if (staticIpProp != null && !SMConfiguration.getInstance().getIpManagement()) { for (NIC nic : veeReplica.getNICs()) { if (nic.getNICConf().getNetwork().getName().contains("public")) { nic.addIPAddress(staticIpProp); System.out.println ("adding " +staticIpProp ); } } } scaleUpPercentage = parser.getScaleUpPercentage(originalVEE.getVEEName()); scaleDownPercentage = parser.getScaleDownPercentage(originalVEE.getVEEName()); lazyScaleDownTime = parser.getScaleDownTime(originalVEE.getVEEName()); if (SMConfiguration.getInstance().getIpManagement()) { for (NIC nic : veeReplica.getNICs()) { String networkName = nic.getNICConf().getNetwork().getName(); if (ips.get(networkName) == null) ips.put(networkName, new ArrayList<String>()); Integer iterations = ipsNeeded.get(networkName); if (iterations == null || iterations == 0) iterations = 1; for (int i = 0; i < iterations; i++) { logger.info("PONG static ip property: "+ staticIpProp); String replicaIP = lcc.getHostAddress(nic.getNICConf() .getNetwork().getNetworkAddresses()[0],staticIpProp); staticIpProp=null; if (replicaIP == null) { abort("Lack of ip addresses"); return null; } // Put the IP in the entrypoint map for this network. Map<String, String> entryPoint = nic.getNICConf() .getNetwork().getEntryPoints(); if (entryPoint.containsKey(originalVEE.getVEEName())) { String ipList = entryPoint .get(originalVEE.getVEEName()); entryPoint.put(originalVEE.getVEEName(), ipList + " " + replicaIP); } else { entryPoint.put(originalVEE.getVEEName(), replicaIP); } nic.addIPAddress(replicaIP); ips.get(networkName).add(replicaIP); } } } HashMap<String, HashMap<String, String>> entryPoints = new HashMap<String, HashMap<String, String>>(); for (Network net : sap.getNetworks()) entryPoints.put(net.getName(), net.getEntryPoints()); try { if (SMConfiguration.getInstance().getIpManagement()) { veeReplica.setOvfRepresentation(parser .inEnvolopeMacroReplacement(originalVEE .getOvfRepresentation(), veeReplica.getId(), SMConfiguration.getInstance().getDomainName(), sap.getFQN().toString(),originalVEE.getFQN().toString(), SMConfiguration .getInstance().getMonitoringAddress(), ips, masks, dnss, gateways, entryPoints)); } else { OVFContextualization context = new OVFContextualization(); /*;*/ System.out.println ("VEE REPLICA OVF " + veeReplica.getOvfRepresentation()); veeReplica.setOvfRepresentation(context.macroReplacement (veeReplica)); } } catch (IOException e) { abort("Unable to create environment file: " + e.getMessage()); } catch (IllegalArgumentException iae) { abort("Some data could not be calculated for the OVF environment: " + iae.getMessage()); } // XXXXXXXXXXXXXXXXXXXXXXXXXX // to be added to OVF: How is a swap disk defined? // XXXXXXXXXXXXXXXXXXXXXXXXXX if (setSwap) { DiskConf swap = new DiskConf(256, null, null); swap.setType("swap"); veeReplica.getVEE().addDiskConf(swap); } else logger.info("Skipping swap disk"); // generate additional image // @SuppressWarnings("unused") if (!SMConfiguration.getInstance().getIpManagement()) { OVFContextualization context = new OVFContextualization(); String pathToCustomizationFile = context.createCustomizationFile(veeReplica); veeReplica.setCustomizationFile (pathToCustomizationFile); } replicas.add(veeReplica); } // deploy the Replica with the newly generated logger.info("Deploying replicas..."); if (deployReplica(replicas)) { for (VEEReplica veeReplica : replicas) { originalVEE.registerVEEReplica(veeReplica); originalVEE.addCurrentReplicas(); try { DbManager.getDbManager().save(veeReplica); } catch (Throwable e) { abort("Error updating the model in the DB: " + e.getMessage()); } } } else return null; return replicas; } private void addRegularReplicaToBalancer(VEEReplica veeReplica, VEE balancerVEE) { logger.info("Adding regular replica to load balancer"); logger.info("Configuring loadbalancer for " + veeReplica.getVEE().getFQN() + " "); String replicaIP = veeReplica.getNICs().iterator().next() .getIPAddresses().iterator().next(); logger.info("Replica IP " + replicaIP); Set<VEEReplica> balancerReplicas = balancerVEE.getVEEReplicas(); if (balancerVEE == null) { logger.error("There is not any balancer"); return; } logger.info("Number of replicas balanced " + balancerReplicas.size()); for (VEEReplica balancer : balancerReplicas) { Set<NIC> nics = balancer.getNICs(); for (NIC nic : nics) { if (!nic.getNICConf().getNetwork().getPrivateNet()) { List<String> addresses = nic.getIPAddresses(); for (String ip : addresses) { if (balancerVEE.getLbManagementPort()==0) { logger.error("No management port for the balancer"); return; } int i =0 ; do { try{ //do what you want to do before sleeping Thread.currentThread().sleep(SMConfiguration.getInstance().getWaitingSecond());//sleep for 1000 ms //do what you want to do after sleeptig } catch(Exception ie){ //If this thread was intrrupted by nother thread } try { int result = this.lbConfigurator.addNode(ip, balancerVEE.getLbManagementPort(), veeReplica.getFQN() .toString(), replicaIP); i = 5; } catch (Exception e) { logger.error("It was impossible to send the load balancer " + balancerVEE.getVEEName() + " " + ip+" : "+balancerVEE.getLbManagementPort()+" the IP information " + replicaIP); } i++; }while (i<SMConfiguration.getInstance().getNumberOfReint()); } } } } } private void removeReplicaFromLoadBalancer(VEEReplica veeReplica, VEE balancerVEE) { logger.info("Removing replica from load balancer: " + veeReplica.getFQN()); if (balancerVEE==null) return; Set<VEEReplica> balancerReplicas = balancerVEE.getVEEReplicas(); for (VEEReplica balancer : balancerReplicas) { Set<NIC> nics = balancer.getNICs(); for (NIC nic : nics) { if (!nic.getNICConf().getNetwork().getPrivateNet()) { List<String> addresses = nic.getIPAddresses(); for (String ip : addresses) { this.lbConfigurator.removeNode(ip, balancerVEE .getLbManagementPort(), veeReplica.getFQN() .toString()); } } } } } }