/** * 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.ovfmanager.ovf.section; import java.math.BigInteger; import javax.xml.bind.JAXBElement; import org.dmtf.schemas.ovf.envelope._1.DiskSectionType; import org.dmtf.schemas.ovf.envelope._1.EnvelopeType; import org.dmtf.schemas.ovf.envelope._1.FileType; import org.dmtf.schemas.ovf.envelope._1.SectionType; import org.dmtf.schemas.ovf.envelope._1.VirtualDiskDescType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.abiquo.ovfmanager.ovf.OVFEnvelopeUtils; import com.abiquo.ovfmanager.ovf.OVFReferenceUtils; import com.abiquo.ovfmanager.ovf.exceptions.IdAlreadyExistsException; import com.abiquo.ovfmanager.ovf.exceptions.IdNotFoundException; import com.abiquo.ovfmanager.ovf.exceptions.InvalidSectionException; import com.abiquo.ovfmanager.ovf.exceptions.SectionException; import com.abiquo.ovfmanager.ovf.exceptions.SectionNotPresentException; public class OVFDiskUtils { private final static Logger log = LoggerFactory.getLogger(OVFDiskUtils.class); /******************************************************************************* * DISK SECTION *******************************************************************************/ public enum DiskSizeUnit { Bytes, KiloBytes, MegaBytes, GigaBytes } // TODO Bits, KiloBits, MegaBits, GigaBits, Words, DoubleWords, QuadWords private static BigInteger toBytes(long size, DiskSizeUnit unit) { BigInteger b1024 = BigInteger.valueOf(1024); BigInteger bytes = BigInteger.valueOf(size); switch (unit) { case GigaBytes: bytes = bytes.multiply(b1024); case MegaBytes: bytes = bytes.multiply(b1024); case KiloBytes: bytes = bytes.multiply(b1024); case Bytes: default: break; } return bytes; } /** * Adds a virtual disk description to mount an existing virtual image file on the provided OVF * envelope. If the fileId is not provided an empty disk is added. Create the DiskSection if * there is any DiskDesc on the OVF envelope. * * @param envelope , the envelope containing the fileId on its references section and where the * virtual disk description will be added. * @param diskId , the required desired disk identifier for the new virtual disk description. * @param fileID , the optional file identifier on the references section to be mounted on the * virtual disk. If any provided its an empty disk. * @param format , the required file image format (hypervisor type) * @param capacity , the required disk capacity. * @param capacityUnit , the optional capacity units. If none specified assumed bytes. * @param populatedSize , the optional expected used size of the disk. * @param parentRefDiskId , the optional parent disk, modified blocks in comparison to a parent * image. * @throw IdNotFound, it the provided fileId is not on the References section or the * parentRefDiskId is not on the Disk section. * @throw IdAlreadyExists, it the provided diskId is already on the Disk section. TODO capacity * can also be property on the envelope "${some.property}" from the ProductSection */ public static void addDiskDescription(EnvelopeType envelope, String diskId, String fileId, DiskFormat format, Long capacity, DiskSizeUnit capacityUnit, Long populatedSize, String parentRefDiskId) throws IdNotFoundException, IdAlreadyExistsException { VirtualDiskDescType disk; FileType file = null; BigInteger byteCapacity; // TODO assert diskId/capacity not null // TODO log info disk = new VirtualDiskDescType(); disk.setDiskId(diskId); disk.setFormat(format.getDiskFormatUri()); // XXX can the referenced file extension be used to infer the disk // format ??? if (fileId != null) { file = OVFReferenceUtils.getReferencedFile(envelope, fileId); disk.setFileRef(fileId); } if (capacityUnit != null && capacityUnit != DiskSizeUnit.Bytes) { disk.setCapacityAllocationUnits(capacityUnit.name()); byteCapacity = toBytes(capacity, capacityUnit); } else { byteCapacity = BigInteger.valueOf(capacity); } // TODO if(capacity.startsWith("$")) disk.setCapacity(String.valueOf(capacity)); // TODO check there aren't any disk with the same fileId. Also assert // the same order with // fileId (references and Disk sections must match) if (populatedSize != null) { if (file == null) { log.error("An empty disk can not have expected used capacity"); } if (populatedSize > byteCapacity.longValue()) { // TODO fail log.error("The populate size ({}b) is higher than the capacity ({}b)", populatedSize, byteCapacity.longValue()); } disk.setPopulatedSize(populatedSize); } if (parentRefDiskId != null) { getDiskDescription(envelope, parentRefDiskId); disk.setParentRef(parentRefDiskId); } else if (file != null) { if (byteCapacity.longValue() < file.getSize().longValue()) { log.error("File size ({}) higher than the specified capacity ({})", file.getSize() .longValue(), byteCapacity.longValue()); } } addDisk(envelope, disk); } /** * Get a specific virtual disk description. * * @param envelope , the OVF envelope to be checked. * @param diskId , the desired disk identifier. * @throws IdNotFoundException if there is any disk with the required identifier on the envelope * disk section. */ public static VirtualDiskDescType getDiskDescription(EnvelopeType envelope, String diskId) throws IdNotFoundException { DiskSectionType sectionDisk; SectionType section; for (JAXBElement< ? extends SectionType> jxbSection : envelope.getSection()) { section = jxbSection.getValue(); if (section instanceof DiskSectionType) { sectionDisk = (DiskSectionType) section; for (VirtualDiskDescType vdisk : sectionDisk.getDisk()) { if (diskId.equals(vdisk.getDiskId())) { return vdisk; } }// disks }// disk section }// sections throw new IdNotFoundException("Virtual disk description id :" + diskId); } /** * TODO use envelope Adds a VirtualDiskDescription to an existing VirtualSystem. * * @throws IdAlreadyExists if the provided VirtualDiscDescription id is already on the * VirtualSystem's DiskSection. */ public static void addDisk(EnvelopeType envelope, VirtualDiskDescType vDisk) throws IdAlreadyExistsException { DiskSectionType sectionDisk = null; try { sectionDisk = OVFEnvelopeUtils.getSection(envelope, DiskSectionType.class); } catch (SectionNotPresentException e) { try { sectionDisk = OVFEnvelopeUtils.createSection(DiskSectionType.class, null); OVFEnvelopeUtils.addSection(envelope, sectionDisk); } catch (SectionException e1) { // from a SectionNotPresentException } } catch (InvalidSectionException invalid) { // Envelope can have disk section } for (VirtualDiskDescType vdd : sectionDisk.getDisk()) { if (vDisk.getDiskId().equalsIgnoreCase(vdd.getDiskId())) { final String msg = "The VirtualDiskDescription diskId" + vDisk.getDiskId(); throw new IdAlreadyExistsException(msg); } } sectionDisk.getDisk().add(vDisk); } /** * TODO use envelope Adds a VirtualDiskDescription to an existing VirtualSystem. * * @throws IdAlreadyExists if the provided VirtualDiscDescription id is already on the * VirtualSystem's DiskSection. */ public static void addDisk(DiskSectionType diskSection, VirtualDiskDescType vDisk) throws IdAlreadyExistsException { for (VirtualDiskDescType vdd : diskSection.getDisk()) { if (vDisk.getDiskId().equalsIgnoreCase(vdd.getDiskId())) { final String msg = "The VirtualDiskDescription diskId" + vDisk.getDiskId(); throw new IdAlreadyExistsException(msg); } } diskSection.getDisk().add(vDisk); } /** * Adds a virtual disk description to mount an existing virtual image file. If the fileId is not * provided an empty disk is added. Create the DiskSection if there is any DiskDesc on the OVF * envelope. This method do not assure fileId is on the EnvelopeReferenceSection (use * addDiskDescription instead) * * @param diskId , the required desired disk identifier for the new virtual disk description. * @param fileID , the optional file identifier on the references section to be mounted on the * virtual disk. If any provided its an empty disk. * @param format , the required file image format (hypervisor type) * @param capacity , the required disk capacity. * @param capacityUnit , the optional capacity units. If none specified assumed bytes. * @param populatedSize , the optional expected used size of the disk. * @param parentRefDiskId , the optional parent disk, modified blocks in comparison to a parent * image. * @throw IdNotFound, it the provided fileId is not on the References section or the * parentRefDiskId is not on the Disk section. * @throw IdAlreadyExists, it the provided diskId is already on the Disk section. TODO capacity * can also be property on the envelope "${some.property}" from the ProductSection */ public static VirtualDiskDescType createDiskDescription(String diskId, String fileId, DiskFormat format, Long capacity, DiskSizeUnit capacityUnit, Long populatedSize, String parentRefDiskId) { VirtualDiskDescType disk; BigInteger byteCapacity; // TODO assert diskId/capacity not null // TODO log info disk = new VirtualDiskDescType(); disk.setDiskId(diskId); disk.setFormat(format.getDiskFormatUri()); if (fileId != null) { // file = OVFReferenceUtils.getReferencedFile(envelope, fileId); disk.setFileRef(fileId); } if (capacityUnit != null && capacityUnit != DiskSizeUnit.Bytes) { disk.setCapacityAllocationUnits(capacityUnit.name()); byteCapacity = toBytes(capacity, capacityUnit); } else { byteCapacity = BigInteger.valueOf(capacity); } // TODO if(capacity.startsWith("$")) disk.setCapacity(String.valueOf(capacity)); // TODO check there aren't any disk with the same fileId. Also assert // the same order with // fileId (references and Disk sections must match) if (populatedSize != null) { if (fileId == null) { log.error("An empty disk can not have expected used capacity"); } if (populatedSize > byteCapacity.longValue()) { // TODO fail log.error("The populate size ({}b) is higher than the capacity ({}b)", populatedSize, byteCapacity.longValue()); } disk.setPopulatedSize(populatedSize); } if (parentRefDiskId != null) { // getDiskDescription(envelope, parentRefDiskId); disk.setParentRef(parentRefDiskId); }/* * else if (file != null) { if (byteCapacity.longValue() < file.getSize().longValue()) { * log.error("File size ({}) higher than the specified capacity ({})", file.getSize() * .longValue(), byteCapacity.longValue()); } } */ return disk; } }