com.abiquo.am.services.download.OVFDocumentFetch.java Source code

Java tutorial

Introduction

Here is the source code for com.abiquo.am.services.download.OVFDocumentFetch.java

Source

/**
 * 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.am.services.download;

import static com.abiquo.am.services.TemplateConventions.getFileUrl;

import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.dmtf.schemas.ovf.envelope._1.ContentType;
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.MsgType;
import org.dmtf.schemas.ovf.envelope._1.ProductSectionType;
import org.dmtf.schemas.ovf.envelope._1.RASDType;
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.springframework.stereotype.Component;

import com.abiquo.am.exceptions.AMError;
import com.abiquo.appliancemanager.client.ExternalHttpConnection;
import com.abiquo.appliancemanager.exceptions.AMException;
import com.abiquo.appliancemanager.exceptions.DownloadException;
import com.abiquo.appliancemanager.transport.MemorySizeUnit;
import com.abiquo.model.enumerator.DiskFormatType;
import com.abiquo.ovfmanager.cim.CIMTypesUtils.CIMResourceTypeEnum;
import com.abiquo.ovfmanager.ovf.OVFEnvelopeUtils;
import com.abiquo.ovfmanager.ovf.exceptions.EmptyEnvelopeException;
import com.abiquo.ovfmanager.ovf.exceptions.InvalidSectionException;
import com.abiquo.ovfmanager.ovf.exceptions.RequiredAttributeException;
import com.abiquo.ovfmanager.ovf.exceptions.SectionAlreadyPresentException;
import com.abiquo.ovfmanager.ovf.exceptions.SectionNotPresentException;
import com.abiquo.ovfmanager.ovf.xml.OVFSerializer;

@Component
public class OVFDocumentFetch {

    /**
     * XXX
     * 
     * @throws DownloadException, if can not connect to the OVF location of if the envelope document
     *             is invalid.
     */
    public EnvelopeType obtainEnvelope(final String ovfId) {
        EnvelopeType envelope;
        InputStream evelopeStream = null;

        final ExternalHttpConnection connection = new ExternalHttpConnection();

        try {
            evelopeStream = connection.openConnection(ovfId);

            envelope = OVFSerializer.getInstance().readXMLEnvelope(evelopeStream);

            envelope = fixOVfDocument(ovfId, envelope);

            checkEnvelopeIsValid(envelope);
        } catch (AMException ame) {
            throw ame;
        } catch (Exception e) {
            throw new AMException(AMError.TEMPLATE_INVALID, e);
        } finally {
            connection.releaseConnection();

            try {
                if (evelopeStream != null) {
                    evelopeStream.close();
                }
            } catch (IOException e) {
                throw new AMException(AMError.TEMPLATE_INSTALL, //
                        "Can't close the http connection to " + ovfId, e);
            }
        }

        return envelope;
    }

    public EnvelopeType fixOVfDocument(final String ovfId, EnvelopeType envelope) {
        try {
            envelope = fixDiskFormtatUriAndFileSizes(envelope, ovfId);
            envelope = fixMissingProductSection(envelope);
        } catch (Exception e) {
            throw new AMException(AMError.TEMPLATE_INVALID, e);
        }

        return envelope;
    }

    public EnvelopeType checkEnvelopeIsValid(final EnvelopeType envelope) {
        try {
            Map<String, VirtualDiskDescType> diskIdToDiskFormat = new HashMap<String, VirtualDiskDescType>();
            Map<String, FileType> fileIdToFileType = new HashMap<String, FileType>();

            DiskSectionType diskSectionType = OVFEnvelopeUtils.getSection(envelope, DiskSectionType.class);

            if (diskSectionType.getDisk().size() != 1) {
                // more than one disk in disk section
                throw new AMException(AMError.TEMPLATE_INVALID_MULTIPLE_DISKS);
            } else {
                int references = 0;
                for (FileType fileType : envelope.getReferences().getFile()) {
                    fileIdToFileType.put(fileType.getId(), fileType);
                    if (diskSectionType.getDisk().get(0).getFileRef().equals(fileType.getId())) {
                        references++;
                    }
                }
                if (references != 1) {
                    // file referenced in diskSection isn't found in file references or found more
                    // than one
                    throw new AMException(AMError.TEMPLATE_INVALID_MULTIPLE_FILES);
                }
            }
            // Create a hash
            for (VirtualDiskDescType virtualDiskDescType : diskSectionType.getDisk()) {
                diskIdToDiskFormat.put(virtualDiskDescType.getDiskId(), virtualDiskDescType);
            }

            // /

            ContentType content = OVFEnvelopeUtils.getTopLevelVirtualSystemContent(envelope);

            if (content instanceof VirtualSystemCollectionType) {
                throw new EmptyEnvelopeException(
                        "Current OVF description document includes a VirtualSystemCollection, "
                                + "abicloud only deal with single virtual system based OVFs");
            }

            VirtualSystemType vsystem = (VirtualSystemType) content;

            VirtualHardwareSectionType hardwareSectionType;
            Integer cpu = null;
            Long hd = null;
            Long ram = null;

            try {
                hardwareSectionType = OVFEnvelopeUtils.getSection(vsystem, VirtualHardwareSectionType.class);
            } catch (InvalidSectionException e) {
                throw new SectionNotPresentException("VirtualHardware on a virtualSystem", e);
            }

            for (RASDType rasdType : hardwareSectionType.getItem()) {

                ResourceType resourceType = rasdType.getResourceType();
                if (resourceType == null) // empty rasd element
                {
                    continue;
                }
                int resTnumeric = Integer.parseInt(resourceType.getValue());

                // Get the information on the ram
                if (CIMResourceTypeEnum.Processor.getNumericResourceType() == resTnumeric) {
                    try {
                        String cpuVal = rasdType.getVirtualQuantity().getValue().toString();

                        cpu = Integer.parseInt(cpuVal);
                    } catch (Exception e) {
                        throw new AMException(AMError.TEMPLATE_INVALID, "Invalid CPU virtualQuantity");
                    }
                } else if (CIMResourceTypeEnum.Memory.getNumericResourceType() == resTnumeric) {
                    try {
                        BigInteger ramVal = rasdType.getVirtualQuantity().getValue();

                        ram = ramVal.longValue();
                    } catch (Exception e) {
                        throw new AMException(AMError.TEMPLATE_INVALID, "Invalid RAM virtualQuantity");
                    }

                    if (rasdType.getAllocationUnits() != null & rasdType.getAllocationUnits().getValue() != null) {
                        final String allocationUnits = rasdType.getAllocationUnits().getValue();

                        final MemorySizeUnit ramSizeUnit = getMemoryUnitsFromOVF(allocationUnits);
                    }
                } else if (CIMResourceTypeEnum.Disk_Drive.getNumericResourceType() == resTnumeric) {
                    // HD requirements are extracted from the associated Disk on ''hostResource''
                    String diskId = getVirtualSystemDiskId(rasdType.getHostResource());

                    if (!diskIdToDiskFormat.containsKey(diskId)) {
                        throw new RequiredAttributeException(
                                "Virtual System makes reference to an undeclared disk " + diskId);
                    }

                    VirtualDiskDescType diskDescType = diskIdToDiskFormat.get(diskId);

                    String capacity = diskDescType.getCapacity();

                    hd = Long.parseLong(capacity);

                    final String allocationUnits = diskDescType.getCapacityAllocationUnits();
                    final MemorySizeUnit hdSizeUnit = getMemoryUnitsFromOVF(allocationUnits);
                }
            } // rasd

            if (cpu == null) {
                throw new RequiredAttributeException("Not CPU RASD element found on the envelope");
            }
            if (ram == null) {
                throw new RequiredAttributeException("Not RAM RASD element found on the envelope");
            }
            if (hd == null) {
                throw new RequiredAttributeException("Not HD RASD element found on the envelope");
            }

        }

        catch (AMException amException) {
            throw amException;
        } catch (Exception e) {
            throw new AMException(AMError.TEMPLATE_INVALID, e);
        }

        return envelope;
    }

    private EnvelopeType fixDiskFormtatUriAndFileSizes(final EnvelopeType envelope, final String ovfId)
            throws SectionNotPresentException, InvalidSectionException {

        DiskSectionType diskSection = OVFEnvelopeUtils.getSection(envelope, DiskSectionType.class);

        if (diskSection.getDisk().size() != 1) {
            final String message = "abicloud only supports single disk definition on the OVF, the current envelope contains multiple disk";
            throw new InvalidSectionException(message);
        }

        VirtualDiskDescType vdisk = diskSection.getDisk().get(0);

        String formatUri = vdisk.getFormat();

        if (StringUtils.isEmpty(formatUri)) {
            final String message = "Missing ''format'' attribute for the Disk element";
            throw new InvalidSectionException(message);
        }

        DiskFormatType format = DiskFormatType.fromURI(formatUri);

        if (format == null) // the format URI isn't on the abicloud enumeration. FIX it
        {
            // vbox/vmware
            // http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized
            // abiquo
            // http://www.vmware.com/technical-resources/interfaces/vmdk_access.html#streamOptimized

            if (formatUri.contains("interfaces/specifications/vmdk.html")) {
                formatUri = formatUri.replace("interfaces/specifications/vmdk.html",
                        "technical-resources/interfaces/vmdk_access.html");

                format = DiskFormatType.fromURI(formatUri);

                if (format == null) {
                    throw new InvalidSectionException(String.format("Invalid disk format type [%s]", formatUri));
                }

                vdisk.setFormat(formatUri);
            }

        }

        try {
            for (FileType ftype : envelope.getReferences().getFile()) {
                if (ftype.getSize() == null) {
                    String fileUrl = getFileUrl(ftype.getHref(), ovfId);
                    Long size = new ExternalHttpConnection().headFile(fileUrl);

                    ftype.setSize(BigInteger.valueOf(size));
                }
            }
        } catch (Exception e) {
            throw new InvalidSectionException(String.format(
                    "Invalid File References section "
                            + "(check all the files on the OVF document contains the ''size'' attribute):\n",
                    e.toString()));
        }

        return envelope;
    }

    /**
     * If product section is not present use the VirtualSystemType to set it.
     * 
     * @throws EmptyEnvelopeException
     */
    private EnvelopeType fixMissingProductSection(final EnvelopeType envelope)
            throws InvalidSectionException, EmptyEnvelopeException {

        ContentType contentType = OVFEnvelopeUtils.getTopLevelVirtualSystemContent(envelope);

        if (!(contentType instanceof VirtualSystemType)) {
            throw new InvalidSectionException("abicloud only suport single virtual system definition,"
                    + " current OVF envelope defines a VirtualSystemCollection");
        }

        VirtualSystemType vsystem = (VirtualSystemType) contentType;

        try {
            OVFEnvelopeUtils.getSection(vsystem, ProductSectionType.class);
        } catch (SectionNotPresentException e) {

            String vsystemName = vsystem.getName() != null && !StringUtils.isEmpty(vsystem.getName().getValue())
                    ? vsystem.getName().getValue()
                    : vsystem.getId();

            MsgType prod = new MsgType();
            prod.setValue(vsystemName);

            ProductSectionType product = new ProductSectionType();
            product.setInfo(vsystem.getInfo());
            product.setProduct(prod);

            try {
                OVFEnvelopeUtils.addSection(vsystem, product);
            } catch (SectionAlreadyPresentException e1) {
            }
        }

        return envelope;
    }

    /**
     * default is byte
     * 
     * @throws RequiredAttributeException
     */
    private static MemorySizeUnit getMemoryUnitsFromOVF(final String allocationUnits)
            throws RequiredAttributeException {

        if (allocationUnits == null || "byte".equalsIgnoreCase(allocationUnits)
                || "bytes".equalsIgnoreCase(allocationUnits)) {
            return MemorySizeUnit.BYTE;
        } else if ("byte * 2^10".equals(allocationUnits) || "KB".equalsIgnoreCase(allocationUnits)
                || "KILOBYTE".equalsIgnoreCase(allocationUnits) || "KILOBYTES".equalsIgnoreCase(allocationUnits)) // kb
        {
            return MemorySizeUnit.KILOBYTE;
        } else if ("byte * 2^20".equals(allocationUnits) || "MB".equalsIgnoreCase(allocationUnits)
                || "MEGABYTE".equalsIgnoreCase(allocationUnits) || "MEGABYTES".equalsIgnoreCase(allocationUnits)) // mb
        {
            return MemorySizeUnit.MEGABYTE;
        } else if ("byte * 2^30".equals(allocationUnits) || "GB".equalsIgnoreCase(allocationUnits)
                || "GIGABYTE".equalsIgnoreCase(allocationUnits) || "GIGABYTES".equalsIgnoreCase(allocationUnits)) // gb
        {
            return MemorySizeUnit.GIGABYTE;
        } else if ("byte * 2^40".equals(allocationUnits) || "TB".equalsIgnoreCase(allocationUnits)
                || "TERABYTE".equalsIgnoreCase(allocationUnits) || "TERABYTES".equalsIgnoreCase(allocationUnits)) // tb
        {
            return MemorySizeUnit.TERABYTE;
        } else {
            final String msg = "Unknow disk capacityAllocationUnits factor [" + allocationUnits + "]";

            throw new RequiredAttributeException(msg);
        }
    }

    /**
     * Decode CimStrings (on the OVF namespce) on the Disk RASD's HostResource attribute to delete
     * the ''ovf://disk/'' prefix
     **/
    private static String getVirtualSystemDiskId(final List<CimString> cimStrs) {
        String cimStringVal = "";
        for (CimString cimString : cimStrs) {
            cimStringVal = cimString.getValue();

            if (cimStringVal.startsWith("ovf:/disk/")) {
                cimStringVal = cimStringVal.replace("ovf:/disk/", "");
                break;
            } else if (cimStringVal.startsWith("/disk/")) {
                cimStringVal = cimStringVal.replace("/disk/", "");
                break;
            }
        }

        return cimStringVal;
    }
}