/**
* Abiquo community edition
* cloud management application for hybrid clouds
* Copyright (C) 2008-2010 - Abiquo Holdings S.L.
*
* This application is free software; you can redistribute it and/or
* modify it under the terms of the GNU LESSER GENERAL PUBLIC
* LICENSE as published by the Free Software Foundation under
* version 3 of the License
*
* This software 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
* LESSER GENERAL PUBLIC LICENSE v.3 for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
package com.abiquo.abiserver.abicloudws;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXBException;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.soap.SOAPException;
import org.dmtf.schemas.ovf.envelope._1.EnvelopeType;
import org.dmtf.schemas.wbem.wsman._1.wsman.SelectorSetType;
import org.dmtf.schemas.wbem.wsman._1.wsman.SelectorType;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import com.abiquo.abiserver.business.hibernate.pojohb.virtualappliance.VirtualappHB;
import com.abiquo.abiserver.business.hibernate.pojohb.virtualhardware.ResourceAllocationSettingData;
import com.abiquo.abiserver.config.AbiConfig;
import com.abiquo.abiserver.config.AbiConfigManager;
import com.abiquo.abiserver.exception.PersistenceException;
import com.abiquo.abiserver.exception.RemoteServiceException;
import com.abiquo.abiserver.exception.VirtualApplianceFaultException;
import com.abiquo.abiserver.exception.VirtualFactoryHealthException;
import com.abiquo.abiserver.model.ovf.OVFModelFactory;
import com.abiquo.abiserver.persistence.hibernate.HibernateUtil;
import com.abiquo.abiserver.pojo.infrastructure.DataCenter;
import com.abiquo.abiserver.pojo.infrastructure.HyperVisor;
import com.abiquo.abiserver.pojo.infrastructure.PhysicalMachine;
import com.abiquo.abiserver.pojo.infrastructure.Rack;
import com.abiquo.abiserver.pojo.infrastructure.VirtualMachine;
import com.abiquo.abiserver.pojo.result.BasicResult;
import com.abiquo.abiserver.pojo.service.RemoteService;
import com.abiquo.abiserver.pojo.virtualappliance.VirtualAppliance;
import com.abiquo.ovfmanager.ovf.xml.OVFSerializer;
import com.abiquo.tracer.ComponentType;
import com.abiquo.tracer.Datacenter;
import com.abiquo.tracer.EventType;
import com.abiquo.tracer.Machine;
import com.abiquo.tracer.Platform;
import com.abiquo.tracer.SeverityType;
import com.abiquo.tracer.client.TracerFactory;
import com.abiquo.util.ErrorManager;
import com.abiquo.util.resources.ResourceManager;
import com.sun.ws.management.client.Resource;
import com.sun.ws.management.client.ResourceFactory;
import com.sun.ws.management.client.exceptions.FaultException;
/**
* This class connects Infrastructure Command with AbiCloud Web Services
*
* @author Oliver
*/
public class InfrastructureWS implements IInfrastructureWS
{
private final static String IDVIRTUALAPP_SQL_BY_VM = "SELECT n.idVirtualApp "
+ "FROM node n, nodevirtualimage ni " + "WHERE n.idNode = ni.idNode and ni.idVM = :id";
/** The logger object */
private final static Logger logger = LoggerFactory.getLogger(InfrastructureWS.class);
// private final static Logger logger = LoggerFactory.getLogger(InfrastructureWS.class);
private final org.dmtf.schemas.wbem.wsman._1.wsman.ObjectFactory managementFactory =
new org.dmtf.schemas.wbem.wsman._1.wsman.ObjectFactory();
private final static OVFSerializer ovfSerializer = OVFSerializer.getInstance();
private final AbiConfig abiConfig = AbiConfigManager.getInstance().getAbiConfig();
static final ResourceManager resourceManager = new ResourceManager(InfrastructureWS.class);
private final ErrorManager errorManager = ErrorManager
.getInstance(AbiCloudConstants.ERROR_PREFIX);
private static Integer bugTimeout;
static
{
try
{
bugTimeout =
Integer.valueOf(System.getProperty("abiquo.virtualfactory.sleepTimeout", "10000"));
}
catch (Exception e)
{
bugTimeout = 10000;
}
System.setProperty("wink.client.connectTimeout", String.valueOf(0));
System.setProperty("wink.client.readTimeout", String.valueOf(0));
}
@Override
public BasicResult setVirtualMachineState(final VirtualMachine virtualMachine,
final String actionState) throws Exception
{
return setVirtualMachineState(virtualMachine, actionState, null);
}
/**
* Update the VM configuration without changing the VM state.
*
* @param virtualMachine The VM to update
* @param additionalRasds The additionsl resources to consider
* @return
* @throws Exception
*/
@Override
public BasicResult updateVirtualMachineConfiguration(final VirtualMachine virtualMachine,
final List<ResourceAllocationSettingData> additionalRasds) throws Exception
{
return setVirtualMachineState(virtualMachine, null, additionalRasds);
}
private BasicResult setVirtualMachineState(final VirtualMachine virtualMachine,
final String actionState, final List<ResourceAllocationSettingData> additionalRasds)
throws Exception
{
BasicResult result = new BasicResult();
try
{
logger.info("Checking Virtual System before the VM operation");
Boolean checkResult = checkVirtualSystem(virtualMachine);
result.setSuccess(checkResult);
if (checkResult)
{
Document doc = changeMachineState(virtualMachine, actionState, additionalRasds);
Resource resource = findResource(virtualMachine);
if (resource != null)
{
result.setSuccess(true);
}
else
{
errorManager.reportError(InfrastructureWS.resourceManager, result,
"resourceNotFound", virtualMachine.getName());
}
Thread.sleep(bugTimeout);
resource.put(doc);
}
else
{
throw new VirtualFactoryHealthException("The virtual machine did not pass the health check.");
}
}
catch (FaultException e)
{
encapsulateAndRethrowFault(virtualMachine, e, actionState);
}
return result;
}
/**
* Creates a virtual machine in the target hypervisor
*
* @param virtualMachine the virtual machine to create
* @deprecated
* @return a basic result
*/
@Deprecated
private BasicResult createVirtualMachine(final VirtualMachine virtualMachine)
{
BasicResult result = null;
try
{
result = new BasicResult();
// HyperVisor hypervisor = (HyperVisor) virtualMachine.getAssignedTo();
Document envelope = createEnvelopeDocument(virtualMachine);
Resource resource =
ResourceFactory.create(getDestinationFromVM(virtualMachine),
AbiCloudConstants.RESOURCE_URI, abiConfig.getTimeout(), envelope,
ResourceFactory.LATEST);
if (resource != null)
{
result.setSuccess(true);
}
else
{
errorManager.reportError(InfrastructureWS.resourceManager, result,
"resourceNotFound", virtualMachine.getName());
}
}
catch (Exception e)
{
errorManager
.reportError(InfrastructureWS.resourceManager, result, "operationFailed", e);
}
return result;
}
/**
* Deletes the virtual machine
*
* @param virtualMachine the virtual machine to delete
* @return a basic result
*/
@Override
public BasicResult deleteVirtualMachine(final VirtualMachine virtualMachine)
{
BasicResult result = null;
try
{
result = new BasicResult();
Resource resource = findResource(virtualMachine);
if (resource != null)
{
result.setSuccess(true);
}
else
{
errorManager.reportError(InfrastructureWS.resourceManager, result,
"resourceNotFound", virtualMachine.getName());
}
resource.delete();
}
catch (Exception e)
{
errorManager
.reportError(InfrastructureWS.resourceManager, result, "operationFailed", e);
}
return result;
}
/*
* (non-Javadoc)
* @see
* com.abiquo.abiserver.abicloudws.IInfrastructureWS#editVirtualMachine(com.abiquo.abiserver
* .pojo.infrastructure.VirtualMachine)
*/
@Override
public BasicResult editVirtualMachine(final VirtualMachine virtualMachine)
{
BasicResult result = new BasicResult();
try
{
logger.info("Checking Virtual machine before the VM operation");
Boolean checkResult = checkVirtualSystem(virtualMachine);
result.setSuccess(checkResult);
if (checkResult)
{
Document doc = createEnvelopeDocument(virtualMachine); // TODO prev updateVS
Resource resource = findResource(virtualMachine);
if (resource != null)
{
result.setSuccess(true);
}
else
{
errorManager.reportError(InfrastructureWS.resourceManager, result,
"resourceNotFound", virtualMachine.getName());
}
resource.put(doc);
}
}
catch (Exception e)
{
errorManager
.reportError(InfrastructureWS.resourceManager, result, "operationFailed", e);
}
return result;
}
/**
* Private helper to create a document with the OVF envelope. This envelope contains the
* information with the virtualMachine creation
*
* @param virtualMachine the virtual machine to get the parameters from
* @return the Document with the new machine values
* @throws JAXBException
* @throws ParserConfigurationException, if the virtual machien can not be mapped to a OVF
* envelope document.
*/
private Document createEnvelopeDocument(final VirtualMachine virtualMachine)
throws JAXBException, ParserConfigurationException
{
EnvelopeType envelope;
try
{
// Creates an OVF envelope from the virtual machine parameters
// [ABICLOUDPREMIUM-1491] When editing a VM we do not perform a state change
envelope =
OVFModelFactory.createOVFModelFromVirtualAppliance().constructEnvelopeType(
virtualMachine, null, null);
// OVFModelFactory.createOVFModelFromVirtualAppliance().getActualState(
// virtualMachine), null);
// envelope =
// OVFModelFactory.createOVFModelFromVirtualAppliance().constructEnvelopeType(
// virtualMachine,
// OVFModelFactory.createOVFModelFromVirtualAppliance().getActualState(
// virtualMachine), null);
}
catch (Exception e)
{
throw new ParserConfigurationException(e.toString());
}
// Updates the changed parameters, preparing for submision
Document doc = ovfSerializer.bindToDocument(envelope, false); // TODO not namespaceaware
return doc;
}
/**
* Private helper to create a document with the information to perform the machine state change.
*
* @param virtualMachine the virtualMachine
* @param machineState the machine State
* @return the document to submit
* @throws Exception
*/
private Document changeMachineState(final VirtualMachine virtualMachine,
final String machineState, final List<ResourceAllocationSettingData> additionalRasds)
throws Exception
{
EnvelopeType envelope =
OVFModelFactory.createOVFModelFromVirtualAppliance().changeMachineState(virtualMachine,
machineState, additionalRasds);
Document doc = ovfSerializer.bindToDocument(envelope, false); // TODO not namespaceaware
return doc;
}
/**
* Private helper to create a selector id with the virtual machine name
*
* @param machineName
* @return
*/
private SelectorSetType createSelectorId(final String machineName)
{
// Creating a selector passing as the id the machine name
SelectorType nameSelectorType = managementFactory.createSelectorType();
nameSelectorType.setName("id");
nameSelectorType.getContent().add(machineName);
SelectorSetType selector = new SelectorSetType();
selector.getSelector().add(nameSelectorType);
return selector;
}
/**
* Private helper to find a resource through the virtualMachine name
*
* @param virtualMachine the virtualMachine to find the resource from
* @return the resource found
* @throws SOAPException
* @throws JAXBException
* @throws IOException
* @throws FaultException
* @throws DatatypeConfigurationException
* @throws PersistenceException
*/
Resource findResource(final VirtualMachine virtualMachine) throws SOAPException, JAXBException,
IOException, FaultException, DatatypeConfigurationException, PersistenceException
{
// Creating a selector passing as the id the machine name
SelectorSetType selector = createSelectorId(virtualMachine.getUUID());
String destination = getDestinationFromVM(virtualMachine);
Resource[] resources =
ResourceFactory.find(destination, AbiCloudConstants.RESOURCE_URI,
abiConfig.getTimeout(), selector);
Resource resource = resources[0];
return resource;
}
/**
* Private helper to get the virtual factory destination address from the virtual machine object
*
* @param virtualMachine the virtual machine
* @return the address destination
* @throws PersistenceException
*/
private String getDestinationFromVM(final VirtualMachine virtualMachine)
throws PersistenceException
{
String destination = null;
HyperVisor hypervisor = (HyperVisor) virtualMachine.getAssignedTo();
PhysicalMachine physicalMachine = (PhysicalMachine) hypervisor.getAssignedTo();
Rack rack = (Rack) physicalMachine.getAssignedTo();
DataCenter dataCenter = rack.getDataCenter();
ArrayList<RemoteService> remoteServices = dataCenter.getRemoteServices();
for (RemoteService remoteService : remoteServices)
{
if (com.abiquo.abiserver.business.hibernate.pojohb.service.RemoteServiceType
.valueOf(remoteService.getRemoteServiceType().getValueOf()) == com.abiquo.abiserver.business.hibernate.pojohb.service.RemoteServiceType.VIRTUAL_FACTORY)
{
destination = remoteService.getUri();
break;
}
}
return destination;
}
/*
* (non-Javadoc)
* @see
* com.abiquo.abiserver.abicloudws.IInfrastructureWS#forceRefreshVirtualMachineState(com.abiquo
* .abiserver.pojo.infrastructure.VirtualMachine)
*/
@Override
public BasicResult forceRefreshVirtualMachineState(final VirtualMachine virtualMachine)
{
logger.info("Forcing refresh of the virtual machine state: {}", virtualMachine.getId());
BasicResult result = new BasicResult();
VirtualappHB virtualappHBPojo = null;
Session session = null;
Transaction transaction = null;
try
{
session = HibernateUtil.getSession();
transaction = session.beginTransaction();
Query query = session.createSQLQuery(IDVIRTUALAPP_SQL_BY_VM);
query.setString("id", virtualMachine.getId().toString());
Integer virtualApplianceId = (Integer) query.uniqueResult();
virtualappHBPojo =
(VirtualappHB) session.get("VirtualappExtendedHB", virtualApplianceId);
VirtualAppliance vapp = virtualappHBPojo.toPojo();
String virtualSystemMonitorAddress =
RemoteServiceUtils.getVirtualSystemMonitorFromVA(vapp);
// EventingSupport.subscribePullEventToVM(virtualMachine, virtualSystemMonitorAddress);
}
catch (PersistenceException e)
{
logger.trace("An error occurred when retrieving the VirtualSystemMonitor",
e.getStackTrace()[0]);
}
catch (RemoteServiceException e)
{
logger.trace("An error occurred when contacting the VirtualSystemMonitor",
e.getStackTrace()[0]);
}
result.setSuccess(true);
return result;
}
/*
* (non-Javadoc)
* @see
* com.abiquo.abiserver.abicloudws.IInfrastructureWS#checkVirtualSystem(com.abiquo.abiserver
* .pojo.infrastructure.VirtualMachine)
*/
@Override
public Boolean checkVirtualSystem(final VirtualMachine virtualMachine)
{
return true;
}
/**
* Encapsulates and rethrows a Fault exception.
* <p>
* This method parses {@link FaultException} to provide human-readable information about the
* failure.
*
* @param vm The virtual machine
* @param ex the exception to encapsulate.
* @param event The event being handled.
* @param message the message to append
* @throws VirtualApplianceFaultException The encapsulated exception.
*/
private void encapsulateAndRethrowFault(final VirtualMachine vm, final FaultException ex,
final EventType event, final String message) throws VirtualApplianceFaultException
{
String exceptionMessage = null;
try
{
// Try to find the original exception details
BufferedReader br = new BufferedReader(new StringReader(ex.getMessage()));
String line = br.readLine();
while (line != null)
{
int detailIndex = line.indexOf("Detail:");
if (detailIndex != -1)
{
int detailBegin = line.lastIndexOf("Exception:");
if (detailBegin != -1)
{
detailBegin += "Exception:".length();
}
else
{
detailBegin = detailIndex + "Detail:".length();
}
exceptionMessage = line.substring(detailBegin + 1, line.length());
break;
}
line = br.readLine();
}
}
catch (IOException ioEx)
{
// Do nothing. Will log the original message.
}
if (exceptionMessage == null)
{
exceptionMessage = ex.getMessage();
}
String logMessage =
message == null ? exceptionMessage : message + "(Caused by: " + exceptionMessage + ")";
traceLog(vm, event, logMessage);
// Rethrow encapsulated exception
throw new VirtualApplianceFaultException(logMessage, ex);
}
/**
* Encapsulates and rethrows a Fault exception.
* <p>
* This method parses {@link FaultException} to provide human-readable information about the
* failure.
*
* @param vm The virtual machine
* @param ex the exception to encapsulate.
* @param event The event being handled.
* @throws VirtualApplianceFaultException The encapsulated exception.
*/
private void encapsulateAndRethrowFault(final VirtualMachine vm, final FaultException ex,
final String actionState) throws VirtualApplianceFaultException
{
encapsulateAndRethrowFault(vm, ex, translateActionToEvent(actionState), null);
}
/**
* Traces a log to tracer.
*
* @param vm the virtual machine information
* @param event The event to trace.
* @param message The message to trace.
*/
private void traceLog(final VirtualMachine vm, final EventType event, final String message)
{
HyperVisor hv = (HyperVisor) vm.getAssignedTo();
PhysicalMachine pm = (PhysicalMachine) hv.getAssignedTo();
Rack rack = (Rack) pm.getAssignedTo();
// Physical Machine information
Machine machine = Machine.machine(pm.getName());
com.abiquo.tracer.Rack tracerRack = com.abiquo.tracer.Rack.rack(rack.getName());
tracerRack.setMachine(machine);
Datacenter datacenter = Datacenter.datacenter(pm.getDataCenter().getName());
datacenter.setRack(tracerRack);
Platform platform = Platform.SYSTEM_PLATFORM;
platform.setDatacenter(datacenter);
// Log to tracer the original message
TracerFactory.getTracer().log(SeverityType.CRITICAL, ComponentType.VIRTUAL_MACHINE, event,
message, platform);
}
/**
* Translate actions to VM to events to trace properly
*
* @param actionState the VM action to translate
* @return the trace Event
*/
private EventType translateActionToEvent(final String actionState)
{
if (actionState == AbiCloudConstants.POWERUP_ACTION)
{
return EventType.VM_POWERON;
}
else if (actionState == AbiCloudConstants.POWERDOWN_ACTION)
{
return EventType.VM_POWEROFF;
}
else if (actionState == AbiCloudConstants.PAUSE_ACTION)
{
return EventType.VM_PAUSED;
}
else if (actionState == AbiCloudConstants.RESUME_ACTION)
{
return EventType.VM_RESUMED;
}
return null;
}
/**
* @deprecated No longer used
*/
@Override
@Deprecated
public BasicResult addVirtualSystem(final VirtualMachine virtualMachine) throws SOAPException,
JAXBException, IOException, FaultException, DatatypeConfigurationException,
ParserConfigurationException
{
BasicResult result = new BasicResult();
Document doc = createEnvelopeDocument(virtualMachine);
Resource resource = findResource(virtualMachine);
if (resource != null)
{
result.setSuccess(true);
}
else
{
errorManager.reportError(InfrastructureWS.resourceManager, result, "resourceNotFound",
virtualMachine.getName());
}
resource.invoke(AbiCloudConstants.ADD_VIRTUALSYSTEM_ACTION, doc);
return result;
}
@Override
public BasicResult removeVirtualSystem(final VirtualMachine virtualMachine)
throws JAXBException, ParserConfigurationException, PersistenceException, SOAPException,
IOException, FaultException, DatatypeConfigurationException
{
BasicResult result = new BasicResult();
result.setSuccess(true);
Document doc = createEnvelopeDocument(virtualMachine); // TODO prev updateVS
Resource resource = findResource(virtualMachine);
if (resource != null)
{
result.setSuccess(true);
}
else
{
errorManager.reportError(InfrastructureWS.resourceManager, result, "resourceNotFound",
virtualMachine.getName());
}
resource.invoke(AbiCloudConstants.REMOVE_VIRTUALSYSTEM_ACTION, doc);
return result;
}
}