/* * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * * The Original Code is available at http://www.abiquo.com/..... * * The Initial Developer of the Original Code is Soluciones Grid, S.L. (www.abiquo.com), * Consell de Cent 296, Principal 2�, 08007 Barcelona, Spain. * * No portions of the Code have been created by third parties. * All Rights Reserved. * * Contributor(s): ______________________________________. * * Graphical User Interface of this software may be used under the terms * of the Common Public Attribution License Version 1.0 (the "CPAL License", * available at http://cpal.abiquo.com/), in which case the * provisions of CPAL License are applicable instead of those above. In relation * of this portions of the Code, a Legal Notice according to Exhibits A and B of * CPAL Licence should be provided in any distribution of the corresponding Code * to Graphical User Interface. */ package com.abiquo.abiserver.abicloudws; import java.io.IOException; import java.math.BigInteger; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.namespace.QName; import javax.xml.soap.SOAPException; import com.abiquo.abiserver.commands.VirtualApplianceCommand; import com.abiquo.abiserver.pojo.infrastructure.HyperVisor; import com.abiquo.abiserver.pojo.infrastructure.State; import com.abiquo.abiserver.pojo.infrastructure.VirtualMachine; import com.abiquo.abiserver.pojo.result.BasicResult; import com.abiquo.abiserver.pojo.virtualappliance.Node; import com.abiquo.abiserver.pojo.virtualappliance.NodeVirtualImage; import com.abiquo.abiserver.pojo.virtualappliance.VirtualAppliance; import com.abiquo.abiserver.pojo.virtualimage.VirtualImage; import org.apache.log4j.Logger; import org.dmtf.schemas.ovf.envelope._1.AnnotationSectionType; import org.dmtf.schemas.ovf.envelope._1.DiskSectionType; import org.dmtf.schemas.ovf.envelope._1.EntityType; import org.dmtf.schemas.ovf.envelope._1.EnvelopeType; import org.dmtf.schemas.ovf.envelope._1.FileType; import org.dmtf.schemas.ovf.envelope._1.RASDType; import org.dmtf.schemas.ovf.envelope._1.ReferencesType; import org.dmtf.schemas.ovf.envelope._1.SectionType; import org.dmtf.schemas.ovf.envelope._1.VSSDType; import org.dmtf.schemas.ovf.envelope._1.VirtualDiskDescType; import org.dmtf.schemas.ovf.envelope._1.VirtualHardwareSectionType; import org.dmtf.schemas.ovf.envelope._1.VirtualSystemCollectionType; import org.dmtf.schemas.ovf.envelope._1.VirtualSystemType; import org.dmtf.schemas.wbem.wscim._1.cim_schema._2.cim_resourceallocationsettingdata.ResourceType; import org.dmtf.schemas.wbem.wscim._1.common.CimString; import org.dmtf.schemas.wbem.wscim._1.common.CimUnsignedLong; import org.dmtf.schemas.wbem.wsman._1.wsman.SelectorSetType; import org.dmtf.schemas.wbem.wsman._1.wsman.SelectorType; import org.w3c.dom.Document; import com.abiquo.abiserver.AbiConfiguration; import com.sun.ws.management.Management; import com.sun.ws.management.client.Resource; import com.sun.ws.management.client.ResourceFactory; import com.sun.ws.management.client.exceptions.FaultException; import com.sun.ws.management.xml.XmlBinding; import com.abiquo.abiserver.AbiConfiguration; import com.abiquo.util.ErrorManager; import com.abiquo.util.resources.ResourceManager; /** * This class connects Virtual Appliance Command with AbiCloud Web Services * * @author pnavarro */ public class VirtualApplianceWS { private XmlBinding binding; private org.dmtf.schemas.ovf.envelope._1.ObjectFactory virtualApplianceFactory = new org.dmtf.schemas.ovf.envelope._1.ObjectFactory(); private final org.dmtf.schemas.wbem.wsman._1.wsman.ObjectFactory managementFactory = new org.dmtf.schemas.wbem.wsman._1.wsman.ObjectFactory(); private final AbiConfiguration abiConfig = AbiConfiguration.getAbiConfiguration(); private static final ResourceManager resourceManager = new ResourceManager(VirtualApplianceWS.class); private final ErrorManager errorManager = ErrorManager.getInstance(AbiCloudConstants.ERROR_PREFIX); /** The logger object */ private final static Logger logger = Logger.getLogger(VirtualApplianceWS.class); public VirtualApplianceWS() throws JAXBException { binding = new XmlBinding(null, "org.dmtf.schemas.ovf.envelope._1"); } /** * Performs a "Start" action in the Virtual Machine * * @param virtualAppliance * @return a BasicResult * @throws IOException * @throws DatatypeConfigurationException * @throws SOAPException * @throws JAXBException * @throws FaultException */ public BasicResult startVirtualAppliance(VirtualAppliance virtualAppliance) throws JAXBException, SOAPException, DatatypeConfigurationException, IOException, FaultException { BasicResult result = new BasicResult(); Resource resource; Document envelope = Management.newDocument(); JAXBElement<EnvelopeType> envelopeElement = createVirtualApplication(virtualAppliance); binding.marshal(envelopeElement, envelope); if (virtualAppliance.getState().getId() == State.NOT_DEPLOYED) { resource = ResourceFactory.create(this.abiConfig.getDestination(), AbiCloudConstants.RESOURCE_URI, this.abiConfig.getTimeout(), envelope, ResourceFactory.LATEST); } else { resource = findResource(virtualAppliance); } if (resource != null) { // Starting the virtual Appliance // Changing the virtualSystems to running Document envelopeRunning = Management.newDocument(); JAXBElement<EnvelopeType> envelopeElementRunning = changeStateVirtualMachine(envelopeElement, AbiCloudConstants.POWERUP_ACTION); binding.marshal(envelopeElementRunning, envelopeRunning); resource.put(envelopeRunning); result.setSuccess(true); } else { this.errorManager.reportError(VirtualApplianceWS.resourceManager, result, "resourceNotFound", virtualAppliance.getName()); } return result; } /** * Performs a "Shutdown" action in the Virtual Machine * * @param virtualAppliance * @return a BasicResult * @throws IOException * @throws DatatypeConfigurationException * @throws SOAPException * @throws JAXBException * @throws FaultException */ public BasicResult shutdownVirtualAppliance(VirtualAppliance virtualAppliance) throws JAXBException, SOAPException, DatatypeConfigurationException, IOException, FaultException { BasicResult result = null; result = new BasicResult(); Document envelopeDoc = Management.newDocument(); JAXBElement<EnvelopeType> envelopeElement = createVirtualApplication(virtualAppliance); Resource resource = findResource(virtualAppliance); if (resource != null) { JAXBElement<EnvelopeType> envelopeElementRunning = changeStateVirtualMachine(envelopeElement, AbiCloudConstants.POWERDOWN_ACTION); binding.marshal(envelopeElementRunning, envelopeDoc); resource.put(envelopeDoc); result.setSuccess(true); } else { this.errorManager.reportError(VirtualApplianceWS.resourceManager, result, "resourceNotFound", virtualAppliance.getName()); } return result; } /** * Deletes a VirtualAppliance that exists in the Data Base * * @param virtualAppliance * @return a BasicResult object, containing success = true if the deletion was successful * @throws DatatypeConfigurationException * @throws FaultException * @throws IOException * @throws JAXBException * @throws SOAPException */ public BasicResult deleteVirtualAppliance(VirtualAppliance virtualAppliance) throws SOAPException, JAXBException, IOException, FaultException, DatatypeConfigurationException { BasicResult result = null; result = new BasicResult(); Resource resource = findResource(virtualAppliance); if (resource != null) { // First shutdown the virtualAppliance // result = shutdownVirtualAppliance(virtualAppliance); result.setSuccess(true); } else { this.errorManager.reportError(VirtualApplianceWS.resourceManager, result, "resourceNotFound", virtualAppliance.getName()); return result; } resource.delete(); return result; } /** * Private helper to create a virtual appliance * * @param virtualAppliance * @return * @throws JAXBException * @throws SOAPException * @throws DatatypeConfigurationException * @throws IOException */ private JAXBElement<EnvelopeType> createVirtualApplication(VirtualAppliance virtualAppliance) throws JAXBException, SOAPException, DatatypeConfigurationException, IOException { // Create an OVF envelope EnvelopeType envelope = virtualApplianceFactory.createEnvelopeType(); VirtualSystemCollectionType virtualSystemCollectionType = virtualApplianceFactory.createVirtualSystemCollectionType(); // Using the name as the virtual System Id virtualSystemCollectionType.setId(String.valueOf(virtualAppliance.getId())); // Creating the references element ReferencesType references = virtualApplianceFactory.createReferencesType(); // Creating the virtual Disk package level element DiskSectionType diskSectionTypePackage = virtualApplianceFactory.createDiskSectionType(); // Getting the virtual Machines List<Node> nodesList = virtualAppliance.getNodes(); for (Node node : nodesList) { if (node instanceof NodeVirtualImage) { NodeVirtualImage nodeVirtualImage = (NodeVirtualImage) node; VirtualMachine virtualMachine = nodeVirtualImage.getVirtualMachine(); VirtualImage virtualImage = nodeVirtualImage.getVirtualImage(); JAXBElement<VirtualSystemType> virtualSystem = createVirtualSystem(virtualMachine, virtualImage); virtualSystemCollectionType.getContent().add(virtualSystem); // Adding the virtual disks to references FileType virtualDiskImageFile = virtualApplianceFactory.createFileType(); virtualDiskImageFile.setId(virtualImage.getName()); // Combining the repository path + the virtual machine relative path String absolutePath = virtualImage.getRepository().getURL() + virtualImage.getPath(); virtualDiskImageFile.setHref(absolutePath); references.getFile().add(virtualDiskImageFile); // Adding the virtual Disks to the package level element VirtualDiskDescType virtualDescTypePackage = virtualApplianceFactory.createVirtualDiskDescType(); virtualDescTypePackage.setDiskId(String.valueOf(virtualImage.getId())); virtualDescTypePackage.setFileRef(virtualImage.getName()); virtualDescTypePackage.setCapacity(String.valueOf(virtualImage.getHdRequired())); diskSectionTypePackage.getDisk().add(virtualDescTypePackage); } } // Adding the virtual System collection to the envelope JAXBElement<VirtualSystemCollectionType> virtualSystemCollection = virtualApplianceFactory.createVirtualSystemCollection(virtualSystemCollectionType); envelope.setContent(virtualSystemCollection); // Adding the references to the envelope envelope.setReferences(references); // Setting the virtual Disk package level element to the envelope JAXBElement<DiskSectionType> diskSectionPackage = virtualApplianceFactory.createDiskSection(diskSectionTypePackage); envelope.getSection().add(diskSectionPackage); JAXBElement<EnvelopeType> envelopeElement = virtualApplianceFactory.createEnvelope(envelope); return envelopeElement; } /** * Private helper to create a Virtual System * * @param virtualMachine the virtual machine to create the virtual system from * @param virtualImage ther virtual image to create the virtual system from * @return */ private JAXBElement<VirtualSystemType> createVirtualSystem(VirtualMachine virtualMachine, VirtualImage virtualImage) { HyperVisor hypervisor = (HyperVisor) virtualMachine.getAssignedTo(); String hypervisorAddres = "http://" + hypervisor.getIp() + ":" + hypervisor.getPort() + "/"; String vsystemType = hypervisor.getName(); String instanceIdString = virtualMachine.getUUID(); String virtualDiskfileId = virtualImage.getName(); String virtualDiskId = String.valueOf(virtualImage.getId()); String hypervisorAddress = hypervisorAddres; int rdPort = virtualMachine.getVdrpPort(); // The Id of the virtualSystem is used for machine name VirtualSystemType virtualSystemType = virtualApplianceFactory.createVirtualSystemType(); // virtualSystemType.setId(machineName); // TODO Using the machine instance UUID as ID virtualSystemType.setId(instanceIdString); // Creating the VirtualHardware element VirtualHardwareSectionType virtualHardwareType = virtualApplianceFactory.createVirtualHardwareSectionType(); VSSDType type = new VSSDType(); // Setting the hypervisor type CimString stringType = new CimString(); stringType.setValue(vsystemType); type.setVirtualSystemType(stringType); virtualHardwareType.setSystem(type); // Setting the hypervisor address as VirtualSystemIdentifier element CimString hyperAddress = new CimString(); hyperAddress.setValue(hypervisorAddress); type.setVirtualSystemIdentifier(hyperAddress); // Setting the virtual machine ID CimString instanceId = new CimString(); instanceId.setValue(instanceIdString); type.setInstanceId(instanceId); List<RASDType> items = virtualHardwareType.getItem(); RASDType ramRasd = virtualApplianceFactory.createRASDType(); CimString ramInstanceId = new CimString(); ramInstanceId.setValue("2"); ramRasd.setInstanceId(ramInstanceId); ResourceType ramResourceType = new ResourceType(); ramResourceType.setValue("4"); ramRasd.setResourceType(ramResourceType); CimUnsignedLong ramUnits = new CimUnsignedLong(); ramUnits.setValue(new BigInteger(String.valueOf(virtualImage.getRamRequired()))); ramRasd.setVirtualQuantity(ramUnits); items.add(ramRasd); RASDType cpuNumberRasd = virtualApplianceFactory.createRASDType(); CimString cpuNumberInstanceId = new CimString(); cpuNumberInstanceId.setValue("1"); cpuNumberRasd.setInstanceId(cpuNumberInstanceId); ResourceType cpuRasd = new ResourceType(); cpuRasd.setValue("3"); cpuNumberRasd.setResourceType(cpuRasd); CimUnsignedLong cpuUnits = new CimUnsignedLong(); cpuUnits.setValue(BigInteger.valueOf(virtualImage.getCpuRequired())); cpuNumberRasd.setVirtualQuantity(cpuUnits); items.add(cpuNumberRasd); // Creating the Annotation Type AnnotationSectionType annotationSectionType = virtualApplianceFactory.createAnnotationSectionType(); Map<QName, String> otherAttributes = annotationSectionType.getOtherAttributes(); otherAttributes.put(AbiCloudConstants.remoteDesktopQname, String.valueOf(rdPort)); logger.debug("The remote desktop port included is: " + String.valueOf(rdPort)); JAXBElement<AnnotationSectionType> annotationElement = virtualApplianceFactory.createAnnotationSection(annotationSectionType); // Setting the Virtual Disk DiskSectionType diskSectionType = virtualApplianceFactory.createDiskSectionType(); VirtualDiskDescType virtualDescType = virtualApplianceFactory.createVirtualDiskDescType(); virtualDescType.setDiskId(virtualDiskId); virtualDescType.setFileRef(virtualDiskfileId); diskSectionType.getDisk().add(virtualDescType); JAXBElement<DiskSectionType> diskSection = virtualApplianceFactory.createDiskSection(diskSectionType); virtualSystemType.getSection().add(diskSection); JAXBElement<VirtualHardwareSectionType> virtualHardwareElement = virtualApplianceFactory.createVirtualHardwareSection(virtualHardwareType); virtualSystemType.getSection().add(virtualHardwareElement); virtualSystemType.getSection().add(annotationElement); JAXBElement<VirtualSystemType> virtualSystemTypeElement = virtualApplianceFactory.createVirtualSystem(virtualSystemType); return virtualSystemTypeElement; } /** * Private helper to change the state * * @param enveloe * @return */ private JAXBElement<EnvelopeType> changeStateVirtualMachine( JAXBElement<EnvelopeType> envelopeElement, String newState) { EnvelopeType envelope = envelopeElement.getValue(); JAXBElement<EntityType> content = (JAXBElement<EntityType>) envelope.getContent(); EntityType entityInstance = content.getValue(); if (entityInstance instanceof VirtualSystemType) { // Getting state property Iterator<JAXBElement< ? extends SectionType>> it = (Iterator<JAXBElement< ? extends SectionType>>) entityInstance.getSection() .iterator(); while (it.hasNext()) { JAXBElement< ? extends SectionType> section = (JAXBElement< ? extends SectionType>) it.next(); SectionType sectionType = section.getValue(); if (sectionType instanceof AnnotationSectionType) { Map<QName, String> attributes = sectionType.getOtherAttributes(); attributes.put(AbiCloudConstants.machineStateQname, newState); } } } else if (entityInstance instanceof VirtualSystemCollectionType) { VirtualSystemCollectionType virtualSystemCollectionType = (VirtualSystemCollectionType) entityInstance; Iterator<JAXBElement< ? extends EntityType>> it = virtualSystemCollectionType.getContent().iterator(); // Changing the state of the VirtualSystems contained in a VirtualSystemCollection while (it.hasNext()) { // Getting state property EntityType subVirtualSystem = it.next().getValue(); String virtualSystemId = subVirtualSystem.getId(); Iterator<JAXBElement< ? extends SectionType>> itSection = (Iterator<JAXBElement< ? extends SectionType>>) subVirtualSystem.getSection() .iterator(); while (itSection.hasNext()) { JAXBElement< ? extends SectionType> section = (JAXBElement< ? extends SectionType>) itSection.next(); SectionType sectionType = section.getValue(); if (sectionType instanceof AnnotationSectionType) { Map<QName, String> attributes = sectionType.getOtherAttributes(); attributes.put(AbiCloudConstants.machineStateQname, newState); } } } } return envelopeElement; } /** * Private helper to find a resource through the virtualAppliance name * * @param virtualAppliance the virtualAppliance to find the resource from * @return the resource found * @throws SOAPException * @throws JAXBException * @throws IOException * @throws FaultException * @throws DatatypeConfigurationException */ private Resource findResource(VirtualAppliance virtualAppliance) throws SOAPException, JAXBException, IOException, FaultException, DatatypeConfigurationException { // Creating a selector passing as the id the machine name SelectorSetType selector = createSelectorId(String.valueOf(virtualAppliance.getId())); Resource[] resources = ResourceFactory.find(this.abiConfig.getDestination(), AbiCloudConstants.RESOURCE_URI, this.abiConfig.getTimeout(), selector); Resource resource = resources[0]; return resource; } /** * Private helper to create a selector id with the virtual application name * * @param virtualApplianceName * @return */ private SelectorSetType createSelectorId(String virtualApplianceName) { // Creating a selector passing as the id the machine name SelectorType nameSelectorType = managementFactory.createSelectorType(); nameSelectorType.setName("id"); nameSelectorType.getContent().add(virtualApplianceName); SelectorSetType selector = new SelectorSetType(); selector.getSelector().add(nameSelectorType); return selector; } /** * Modifies the information of a VirtualAppliance that already exists in the Data Base * * @param virtualAppliance * @return A DataResult object, containing a list of nodes modified */ public BasicResult editVirtualAppliance(VirtualAppliance virtualAppliance) throws SOAPException, JAXBException, IOException, FaultException, DatatypeConfigurationException { BasicResult result = null; result = new BasicResult(); if (virtualAppliance.getState().getId() == State.RUNNING) { Document envelope = Management.newDocument(); JAXBElement<EnvelopeType> envelopeElement = createVirtualApplication(virtualAppliance); binding.marshal(envelopeElement, envelope); Resource resource = findResource(virtualAppliance); if (resource != null) { // Starting the virtual Appliance // Changing the virtualSystems to running Document envelopeRunning = Management.newDocument(); JAXBElement<EnvelopeType> envelopeElementRunning = changeStateVirtualMachine(envelopeElement, AbiCloudConstants.POWERUP_ACTION); binding.marshal(envelopeElementRunning, envelopeRunning); resource.put(envelopeRunning); result.setSuccess(true); } else { this.errorManager.reportError(VirtualApplianceWS.resourceManager, result, "resourceNotFound", virtualAppliance.getName()); } } else { result.setSuccess(true); } return result; } }