diff --git a/api/src/com/cloud/storage/Storage.java b/api/src/com/cloud/storage/Storage.java index f1868a7a1b3..2175c9b1a0c 100755 --- a/api/src/com/cloud/storage/Storage.java +++ b/api/src/com/cloud/storage/Storage.java @@ -28,6 +28,8 @@ public class Storage { OVA(true, true, true, "ova"), VHDX(true, true, true, "vhdx"), BAREMETAL(false, false, false, "BAREMETAL"), + VMDK(true, true, false, "vmdk"), + VDI(true, true, false, "vdi"), TAR(false, false, false, "tar"); private final boolean thinProvisioned; diff --git a/core/src/com/cloud/storage/template/OVAProcessor.java b/core/src/com/cloud/storage/template/OVAProcessor.java new file mode 100644 index 00000000000..0db3bb00e0a --- /dev/null +++ b/core/src/com/cloud/storage/template/OVAProcessor.java @@ -0,0 +1,158 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.storage.template; + +import java.io.File; +import java.util.Map; + +import javax.ejb.Local; +import javax.naming.ConfigurationException; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.apache.log4j.Logger; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import com.cloud.exception.InternalErrorException; +import com.cloud.storage.Storage.ImageFormat; +import com.cloud.storage.StorageLayer; +import com.cloud.utils.component.AdapterBase; +import com.cloud.utils.script.Script; + +@Local(value = Processor.class) +public class OVAProcessor extends AdapterBase implements Processor { + private static final Logger s_logger = Logger.getLogger(OVAProcessor.class); + + StorageLayer _storage; + + @Override + public FormatInfo process(String templatePath, ImageFormat format, String templateName) throws InternalErrorException { + if (format != null) { + if (s_logger.isInfoEnabled()) { + s_logger.info("We currently don't handle conversion from " + format + " to OVA."); + } + return null; + } + + s_logger.info("Template processing. templatePath: " + templatePath + ", templateName: " + templateName); + String templateFilePath = templatePath + File.separator + templateName + "." + ImageFormat.OVA.getFileExtension(); + if (!_storage.exists(templateFilePath)) { + if (s_logger.isInfoEnabled()) { + s_logger.info("Unable to find the vmware template file: " + templateFilePath); + } + return null; + } + + s_logger.info("Template processing - untar OVA package. templatePath: " + templatePath + ", templateName: " + templateName); + String templateFileFullPath = templatePath + File.separator + templateName + "." + ImageFormat.OVA.getFileExtension(); + File templateFile = new File(templateFileFullPath); + + Script command = new Script("tar", 0, s_logger); + command.add("--no-same-owner"); + command.add("-xf", templateFileFullPath); + command.setWorkDir(templateFile.getParent()); + String result = command.execute(); + if (result != null) { + s_logger.info("failed to untar OVA package due to " + result + ". templatePath: " + templatePath + ", templateName: " + templateName); + return null; + } + + FormatInfo info = new FormatInfo(); + info.format = ImageFormat.OVA; + info.filename = templateName + "." + ImageFormat.OVA.getFileExtension(); + info.size = _storage.getSize(templateFilePath); + info.virtualSize = getTemplateVirtualSize(templatePath, info.filename); + + // delete original OVA file + // templateFile.delete(); + return info; + } + + @Override + public Long getVirtualSize(File file) { + try { + long size = getTemplateVirtualSize(file.getParent(), file.getName()); + return size; + } catch (Exception e) { + + } + return file.length(); + } + + public long getTemplateVirtualSize(String templatePath, String templateName) throws InternalErrorException { + // get the virtual size from the OVF file meta data + long virtualSize = 0; + String templateFileFullPath = templatePath.endsWith(File.separator) ? templatePath : templatePath + File.separator; + templateFileFullPath += templateName.endsWith(ImageFormat.OVA.getFileExtension()) ? templateName : templateName + "." + ImageFormat.OVA.getFileExtension(); + String ovfFileName = getOVFFilePath(templateFileFullPath); + if (ovfFileName == null) { + String msg = "Unable to locate OVF file in template package directory: " + templatePath; + s_logger.error(msg); + throw new InternalErrorException(msg); + } + try { + Document ovfDoc = null; + ovfDoc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new File(ovfFileName)); + Element disk = (Element)ovfDoc.getElementsByTagName("Disk").item(0); + virtualSize = Long.parseLong(disk.getAttribute("ovf:capacity")); + String allocationUnits = disk.getAttribute("ovf:capacityAllocationUnits"); + if ((virtualSize != 0) && (allocationUnits != null)) { + long units = 1; + if (allocationUnits.equalsIgnoreCase("KB") || allocationUnits.equalsIgnoreCase("KiloBytes") || allocationUnits.equalsIgnoreCase("byte * 2^10")) { + units = 1024; + } else if (allocationUnits.equalsIgnoreCase("MB") || allocationUnits.equalsIgnoreCase("MegaBytes") || allocationUnits.equalsIgnoreCase("byte * 2^20")) { + units = 1024 * 1024; + } else if (allocationUnits.equalsIgnoreCase("GB") || allocationUnits.equalsIgnoreCase("GigaBytes") || allocationUnits.equalsIgnoreCase("byte * 2^30")) { + units = 1024 * 1024 * 1024; + } + virtualSize = virtualSize * units; + } else { + throw new InternalErrorException("Failed to read capacity and capacityAllocationUnits from the OVF file: " + ovfFileName); + } + return virtualSize; + } catch (Exception e) { + String msg = "Unable to parse OVF XML document to get the virtual disk size due to" + e; + s_logger.error(msg); + throw new InternalErrorException(msg); + } + } + + private String getOVFFilePath(String srcOVAFileName) { + File file = new File(srcOVAFileName); + assert (_storage != null); + String[] files = _storage.listFiles(file.getParent()); + if (files != null) { + for (String fileName : files) { + if (fileName.toLowerCase().endsWith(".ovf")) { + File ovfFile = new File(fileName); + return file.getParent() + File.separator + ovfFile.getName(); + } + } + } + return null; + } + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + _storage = (StorageLayer)params.get(StorageLayer.InstanceConfigKey); + if (_storage == null) { + throw new ConfigurationException("Unable to get storage implementation"); + } + + return true; + } +} diff --git a/core/src/com/cloud/storage/template/VmdkProcessor.java b/core/src/com/cloud/storage/template/VmdkProcessor.java index be201438a1c..2c08447e9f9 100644 --- a/core/src/com/cloud/storage/template/VmdkProcessor.java +++ b/core/src/com/cloud/storage/template/VmdkProcessor.java @@ -16,22 +16,24 @@ // under the License. package com.cloud.storage.template; +import java.io.BufferedReader; import java.io.File; +import java.io.FileReader; +import java.io.FileNotFoundException; +import java.io.IOException; import java.util.Map; +import java.util.regex.Pattern; +import java.util.regex.Matcher; import javax.ejb.Local; import javax.naming.ConfigurationException; -import javax.xml.parsers.DocumentBuilderFactory; import org.apache.log4j.Logger; -import org.w3c.dom.Document; -import org.w3c.dom.Element; import com.cloud.exception.InternalErrorException; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.StorageLayer; import com.cloud.utils.component.AdapterBase; -import com.cloud.utils.script.Script; @Local(value = Processor.class) public class VmdkProcessor extends AdapterBase implements Processor { @@ -49,7 +51,7 @@ public class VmdkProcessor extends AdapterBase implements Processor { } s_logger.info("Template processing. templatePath: " + templatePath + ", templateName: " + templateName); - String templateFilePath = templatePath + File.separator + templateName + "." + ImageFormat.OVA.getFileExtension(); + String templateFilePath = templatePath + File.separator + templateName + "." + ImageFormat.VMDK.getFileExtension(); if (!_storage.exists(templateFilePath)) { if (s_logger.isInfoEnabled()) { s_logger.info("Unable to find the vmware template file: " + templateFilePath); @@ -57,28 +59,12 @@ public class VmdkProcessor extends AdapterBase implements Processor { return null; } - s_logger.info("Template processing - untar OVA package. templatePath: " + templatePath + ", templateName: " + templateName); - String templateFileFullPath = templatePath + File.separator + templateName + "." + ImageFormat.OVA.getFileExtension(); - File templateFile = new File(templateFileFullPath); - - Script command = new Script("tar", 0, s_logger); - command.add("--no-same-owner"); - command.add("-xf", templateFileFullPath); - command.setWorkDir(templateFile.getParent()); - String result = command.execute(); - if (result != null) { - s_logger.info("failed to untar OVA package due to " + result + ". templatePath: " + templatePath + ", templateName: " + templateName); - return null; - } - FormatInfo info = new FormatInfo(); - info.format = ImageFormat.OVA; - info.filename = templateName + "." + ImageFormat.OVA.getFileExtension(); + info.format = ImageFormat.VMDK; + info.filename = templateName + "." + ImageFormat.VMDK.getFileExtension(); info.size = _storage.getSize(templateFilePath); info.virtualSize = getTemplateVirtualSize(templatePath, info.filename); - // delete original OVA file - // templateFile.delete(); return info; } @@ -94,56 +80,37 @@ public class VmdkProcessor extends AdapterBase implements Processor { } public long getTemplateVirtualSize(String templatePath, String templateName) throws InternalErrorException { - // get the virtual size from the OVF file meta data long virtualSize = 0; String templateFileFullPath = templatePath.endsWith(File.separator) ? templatePath : templatePath + File.separator; - templateFileFullPath += templateName.endsWith(ImageFormat.OVA.getFileExtension()) ? templateName : templateName + "." + ImageFormat.OVA.getFileExtension(); - String ovfFileName = getOVFFilePath(templateFileFullPath); - if (ovfFileName == null) { - String msg = "Unable to locate OVF file in template package directory: " + templatePath; - s_logger.error(msg); - throw new InternalErrorException(msg); - } - try { - Document ovfDoc = null; - ovfDoc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new File(ovfFileName)); - Element disk = (Element)ovfDoc.getElementsByTagName("Disk").item(0); - virtualSize = Long.parseLong(disk.getAttribute("ovf:capacity")); - String allocationUnits = disk.getAttribute("ovf:capacityAllocationUnits"); - if ((virtualSize != 0) && (allocationUnits != null)) { - long units = 1; - if (allocationUnits.equalsIgnoreCase("KB") || allocationUnits.equalsIgnoreCase("KiloBytes") || allocationUnits.equalsIgnoreCase("byte * 2^10")) { - units = 1024; - } else if (allocationUnits.equalsIgnoreCase("MB") || allocationUnits.equalsIgnoreCase("MegaBytes") || allocationUnits.equalsIgnoreCase("byte * 2^20")) { - units = 1024 * 1024; - } else if (allocationUnits.equalsIgnoreCase("GB") || allocationUnits.equalsIgnoreCase("GigaBytes") || allocationUnits.equalsIgnoreCase("byte * 2^30")) { - units = 1024 * 1024 * 1024; - } - virtualSize = virtualSize * units; - } else { - throw new InternalErrorException("Failed to read capacity and capacityAllocationUnits from the OVF file: " + ovfFileName); - } - return virtualSize; - } catch (Exception e) { - String msg = "Unable to parse OVF XML document to get the virtual disk size due to" + e; - s_logger.error(msg); - throw new InternalErrorException(msg); - } - } + templateFileFullPath += templateName.endsWith(ImageFormat.VMDK.getFileExtension()) ? templateName : templateName + "." + ImageFormat.VMDK.getFileExtension(); + String vmdkHeader = ""; - private String getOVFFilePath(String srcOVAFileName) { - File file = new File(srcOVAFileName); - assert (_storage != null); - String[] files = _storage.listFiles(file.getParent()); - if (files != null) { - for (String fileName : files) { - if (fileName.toLowerCase().endsWith(".ovf")) { - File ovfFile = new File(fileName); - return file.getParent() + File.separator + ovfFile.getName(); + try { + FileReader fileReader = new FileReader(templateFileFullPath); + BufferedReader bufferedReader = new BufferedReader(fileReader); + Pattern regex = Pattern.compile("(RW|RDONLY|NOACCESS) (\\d+) (FLAT|SPARSE|ZERO|VMFS|VMFSSPARSE|VMFSDRM|VMFSRAW)"); + String line = null; + while((line = bufferedReader.readLine()) != null) { + Matcher m = regex.matcher(line); + if (m.find( )) { + long sectors = Long.parseLong(m.group(2)); + virtualSize = sectors * 512; + break; } } + bufferedReader.close(); + } catch(FileNotFoundException ex) { + String msg = "Unable to open file '" + templateFileFullPath + "' " + ex.toString(); + s_logger.error(msg); + throw new InternalErrorException(msg); + } catch(IOException ex) { + String msg = "Unable read open file '" + templateFileFullPath + "' " + ex.toString(); + s_logger.error(msg); + throw new InternalErrorException(msg); } - return null; + + s_logger.debug("vmdk file had size="+virtualSize); + return virtualSize; } @Override diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java index d854ca57e38..7d5d3351220 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java @@ -189,6 +189,7 @@ public class KVMStorageProcessor implements StorageProcessor { } /* Copy volume to primary storage */ + s_logger.debug("Copying template to primary storage, template format is " + tmplVol.getFormat() ); KVMStoragePool primaryPool = storagePoolMgr.getStoragePool(primaryStore.getPoolType(), primaryStore.getUuid()); KVMPhysicalDisk primaryVol = null; diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java index 82d0f8d41cf..f910813ec5c 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java @@ -978,6 +978,7 @@ public class LibvirtStorageAdaptor implements StorageAdaptor { String sourcePath = disk.getPath(); KVMPhysicalDisk newDisk; + s_logger.debug("copyPhysicalDisk: disk size:" + disk.getSize() + ", virtualsize:" + disk.getVirtualSize()+" format:"+disk.getFormat()); if (destPool.getType() != StoragePoolType.RBD) { if (disk.getFormat() == PhysicalDiskFormat.TAR) { newDisk = destPool.createPhysicalDisk(name, PhysicalDiskFormat.DIR, disk.getVirtualSize()); @@ -1015,7 +1016,8 @@ public class LibvirtStorageAdaptor implements StorageAdaptor { try { Map info = qemu.info(srcFile); String backingFile = info.get(new String("backing_file")); - if (sourceFormat.equals(destFormat) && backingFile == null) { + // qcow2 templates can just be copied into place + if (sourceFormat.equals(destFormat) && backingFile == null && sourcePath.endsWith(".qcow2")) { String result = Script.runSimpleBashScript("cp -f " + sourcePath + " " + destPath, timeout); if (result != null) { throw new CloudRuntimeException("Failed to create disk: " + result); diff --git a/plugins/hypervisors/kvm/src/org/apache/cloudstack/utils/qemu/QemuImg.java b/plugins/hypervisors/kvm/src/org/apache/cloudstack/utils/qemu/QemuImg.java index 8c23f1ee802..a948ca1899f 100644 --- a/plugins/hypervisors/kvm/src/org/apache/cloudstack/utils/qemu/QemuImg.java +++ b/plugins/hypervisors/kvm/src/org/apache/cloudstack/utils/qemu/QemuImg.java @@ -184,8 +184,9 @@ public class QemuImg { public void convert(QemuImgFile srcFile, QemuImgFile destFile, Map options) throws QemuImgException { Script s = new Script(_qemuImgPath, timeout); s.add("convert"); - s.add("-f"); - s.add(srcFile.getFormat().toString()); + // autodetect source format. Sometime int he future we may teach KVMPhysicalDisk about more formats, then we can explicitly pass them if necessary + //s.add("-f"); + //s.add(srcFile.getFormat().toString()); s.add("-O"); s.add(destFile.getFormat().toString()); @@ -350,4 +351,4 @@ public class QemuImg { public void resize(QemuImgFile file, long size) throws QemuImgException { this.resize(file, size, false); } -} \ No newline at end of file +} diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java index 040a4cfd8f3..cd3fe733828 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java @@ -80,7 +80,7 @@ import com.cloud.storage.JavaStorageLayer; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.StorageLayer; import com.cloud.storage.Volume; -import com.cloud.storage.template.VmdkProcessor; +import com.cloud.storage.template.OVAProcessor; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.utils.StringUtils; @@ -649,10 +649,10 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager { clonedVm.exportVm(secondaryMountPoint + "/" + installPath, templateUniqueName, true, false); long physicalSize = new File(installFullPath + "/" + templateUniqueName + ".ova").length(); - VmdkProcessor processor = new VmdkProcessor(); + OVAProcessor processor = new OVAProcessor(); Map params = new HashMap(); params.put(StorageLayer.InstanceConfigKey, _storage); - processor.configure("VMDK Processor", params); + processor.configure("OVA Processor", params); long virtualSize = processor.getTemplateVirtualSize(installFullPath, templateUniqueName); postCreatePrivateTemplate(installFullPath, templateId, templateUniqueName, physicalSize, virtualSize); @@ -771,11 +771,11 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager { } long physicalSize = new File(installFullPath + "/" + templateVMDKName).length(); - VmdkProcessor processor = new VmdkProcessor(); + OVAProcessor processor = new OVAProcessor(); // long physicalSize = new File(installFullPath + "/" + templateUniqueName + ".ova").length(); Map params = new HashMap(); params.put(StorageLayer.InstanceConfigKey, _storage); - processor.configure("VMDK Processor", params); + processor.configure("OVA Processor", params); long virtualSize = processor.getTemplateVirtualSize(installFullPath, templateUniqueName); postCreatePrivateTemplate(installFullPath, templateId, templateUniqueName, physicalSize, virtualSize); diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java index b55dbec9dae..abb673328d3 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java @@ -78,7 +78,7 @@ import com.cloud.storage.JavaStorageLayer; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.StorageLayer; import com.cloud.storage.Volume; -import com.cloud.storage.template.VmdkProcessor; +import com.cloud.storage.template.OVAProcessor; import com.cloud.utils.Pair; import com.cloud.utils.Ternary; import com.cloud.utils.script.Script; @@ -617,10 +617,10 @@ public class VmwareStorageProcessor implements StorageProcessor { clonedVm.exportVm(secondaryMountPoint + "/" + installPath, templateUniqueName, true, false); long physicalSize = new File(installFullPath + "/" + templateUniqueName + ".ova").length(); - VmdkProcessor processor = new VmdkProcessor(); + OVAProcessor processor = new OVAProcessor(); Map params = new HashMap(); params.put(StorageLayer.InstanceConfigKey, _storage); - processor.configure("VMDK Processor", params); + processor.configure("OVA Processor", params); long virtualSize = processor.getTemplateVirtualSize(installFullPath, templateUniqueName); postCreatePrivateTemplate(installFullPath, templateId, templateUniqueName, physicalSize, virtualSize); @@ -841,11 +841,11 @@ public class VmwareStorageProcessor implements StorageProcessor { } long physicalSize = new File(installFullPath + "/" + templateVMDKName).length(); - VmdkProcessor processor = new VmdkProcessor(); + OVAProcessor processor = new OVAProcessor(); // long physicalSize = new File(installFullPath + "/" + templateUniqueName + ".ova").length(); Map params = new HashMap(); params.put(StorageLayer.InstanceConfigKey, _storage); - processor.configure("VMDK Processor", params); + processor.configure("OVA Processor", params); long virtualSize = processor.getTemplateVirtualSize(installFullPath, templateUniqueName); postCreatePrivateTemplate(installFullPath, templateId, templateUniqueName, physicalSize, virtualSize); diff --git a/server/src/com/cloud/template/HypervisorTemplateAdapter.java b/server/src/com/cloud/template/HypervisorTemplateAdapter.java index 74d1ac85b4f..25e79db2bbe 100755 --- a/server/src/com/cloud/template/HypervisorTemplateAdapter.java +++ b/server/src/com/cloud/template/HypervisorTemplateAdapter.java @@ -151,21 +151,54 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase { (!url.toLowerCase().endsWith("qcow2.bz2")) && (!url.toLowerCase().endsWith("qcow2.gz")) && (!url.toLowerCase().endsWith("ova")) && (!url.toLowerCase().endsWith("ova.zip")) && (!url.toLowerCase().endsWith("ova.bz2")) && (!url.toLowerCase().endsWith("ova.gz")) && (!url.toLowerCase().endsWith("tar")) && (!url.toLowerCase().endsWith("tar.zip")) && (!url.toLowerCase().endsWith("tar.bz2")) && - (!url.toLowerCase().endsWith("tar.gz")) && (!url.toLowerCase().endsWith("img")) && (!url.toLowerCase().endsWith("raw"))) { + (!url.toLowerCase().endsWith("tar.gz")) && (!url.toLowerCase().endsWith("vmdk")) && (!url.toLowerCase().endsWith("vmdk.gz")) && + (!url.toLowerCase().endsWith("vmdk.zip")) && (!url.toLowerCase().endsWith("vmdk.bz2")) && (!url.toLowerCase().endsWith("img")) && + (!url.toLowerCase().endsWith("img.gz")) && (!url.toLowerCase().endsWith("img.zip")) && (!url.toLowerCase().endsWith("img.bz2")) && + (!url.toLowerCase().endsWith("raw")) && (!url.toLowerCase().endsWith("raw.gz")) && (!url.toLowerCase().endsWith("raw.bz2")) && + (!url.toLowerCase().endsWith("raw.zip"))) { throw new InvalidParameterValueException("Please specify a valid " + format.toLowerCase()); } - if ((format.equalsIgnoreCase("vhd") && (!url.toLowerCase().endsWith("vhd") && !url.toLowerCase().endsWith("vhd.zip") && !url.toLowerCase().endsWith("vhd.bz2") && !url.toLowerCase() - .endsWith("vhd.gz"))) || - (format.equalsIgnoreCase("vhdx") && (!url.toLowerCase().endsWith("vhdx") && !url.toLowerCase().endsWith("vhdx.zip") && - !url.toLowerCase().endsWith("vhdx.bz2") && !url.toLowerCase() - .endsWith("vhdx.gz"))) || - (format.equalsIgnoreCase("qcow2") && (!url.toLowerCase().endsWith("qcow2") && !url.toLowerCase().endsWith("qcow2.zip") && - !url.toLowerCase().endsWith("qcow2.bz2") && !url.toLowerCase().endsWith("qcow2.gz"))) || - (format.equalsIgnoreCase("ova") && (!url.toLowerCase().endsWith("ova") && !url.toLowerCase().endsWith("ova.zip") && !url.toLowerCase().endsWith("ova.bz2") && !url.toLowerCase() - .endsWith("ova.gz"))) || - (format.equalsIgnoreCase("tar") && (!url.toLowerCase().endsWith("tar") && !url.toLowerCase().endsWith("tar.zip") && !url.toLowerCase().endsWith("tar.bz2") && !url.toLowerCase() - .endsWith("tar.gz"))) || (format.equalsIgnoreCase("raw") && (!url.toLowerCase().endsWith("img") && !url.toLowerCase().endsWith("raw")))) { + if ((format.equalsIgnoreCase("vhd") + && (!url.toLowerCase().endsWith("vhd") + && !url.toLowerCase().endsWith("vhd.zip") + && !url.toLowerCase().endsWith("vhd.bz2") + && !url.toLowerCase().endsWith("vhd.gz"))) + || (format.equalsIgnoreCase("vhdx") + && (!url.toLowerCase().endsWith("vhdx") + && !url.toLowerCase().endsWith("vhdx.zip") + && !url.toLowerCase().endsWith("vhdx.bz2") + && !url.toLowerCase().endsWith("vhdx.gz"))) + || (format.equalsIgnoreCase("qcow2") + && (!url.toLowerCase().endsWith("qcow2") + && !url.toLowerCase().endsWith("qcow2.zip") + && !url.toLowerCase().endsWith("qcow2.bz2") + && !url.toLowerCase().endsWith("qcow2.gz"))) + || (format.equalsIgnoreCase("ova") + && (!url.toLowerCase().endsWith("ova") + && !url.toLowerCase().endsWith("ova.zip") + && !url.toLowerCase().endsWith("ova.bz2") + && !url.toLowerCase().endsWith("ova.gz"))) + || (format.equalsIgnoreCase("tar") + && (!url.toLowerCase().endsWith("tar") + && !url.toLowerCase().endsWith("tar.zip") + && !url.toLowerCase().endsWith("tar.bz2") + && !url.toLowerCase().endsWith("tar.gz"))) + || (format.equalsIgnoreCase("raw") + && (!url.toLowerCase().endsWith("img") + && !url.toLowerCase().endsWith("img.zip") + && !url.toLowerCase().endsWith("img.bz2") + && !url.toLowerCase().endsWith("img.gz") + && !url.toLowerCase().endsWith("raw") + && !url.toLowerCase().endsWith("raw.bz2") + && !url.toLowerCase().endsWith("raw.zip") + && !url.toLowerCase().endsWith("raw.gz"))) + || (format.equalsIgnoreCase("vmdk") + && (!url.toLowerCase().endsWith("vmdk") + && !url.toLowerCase().endsWith("vmdk.zip") + && !url.toLowerCase().endsWith("vmdk.bz2") + && !url.toLowerCase().endsWith("vmdk.gz"))) + ) { throw new InvalidParameterValueException("Please specify a valid URL. URL:" + url + " is an invalid for the format " + format.toLowerCase()); } diff --git a/services/secondary-storage/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java b/services/secondary-storage/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java index 7c1b9c8aa95..00c1aac77d7 100755 --- a/services/secondary-storage/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java +++ b/services/secondary-storage/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java @@ -125,6 +125,7 @@ import com.cloud.storage.template.RawImageProcessor; import com.cloud.storage.template.TemplateLocation; import com.cloud.storage.template.TemplateProp; import com.cloud.storage.template.VhdProcessor; +import com.cloud.storage.template.OVAProcessor; import com.cloud.storage.template.VmdkProcessor; import com.cloud.utils.NumbersUtil; import com.cloud.utils.S3Utils; @@ -771,6 +772,8 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S if (ext != null) { if (ext.equalsIgnoreCase("vhd")) { return ImageFormat.VHD; + } else if (ext.equalsIgnoreCase("vhdx")) { + return ImageFormat.VHDX; } else if (ext.equalsIgnoreCase("qcow2")) { return ImageFormat.QCOW2; } else if (ext.equalsIgnoreCase("ova")) { @@ -779,6 +782,10 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S return ImageFormat.TAR; } else if (ext.equalsIgnoreCase("img") || ext.equalsIgnoreCase("raw")) { return ImageFormat.RAW; + } else if (ext.equalsIgnoreCase("vmdk")) { + return ImageFormat.VMDK; + } else if (ext.equalsIgnoreCase("vdi")) { + return ImageFormat.VDI; } } @@ -794,11 +801,13 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S } else if (format == ImageFormat.QCOW2) { processor = new QCOW2Processor(); } else if (format == ImageFormat.OVA) { - processor = new VmdkProcessor(); + processor = new OVAProcessor(); } else if (format == ImageFormat.VHD) { processor = new VhdProcessor(); } else if (format == ImageFormat.RAW) { processor = new RawImageProcessor(); + } else if (format == ImageFormat.VMDK) { + processor = new VmdkProcessor(); } if (processor == null) { @@ -840,7 +849,10 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S if (!srcFile.exists()) { srcFile = _storage.getFile(templatePath + ".ova"); if (!srcFile.exists()) { - return new CopyCmdAnswer("Can't find src file:" + templatePath); + srcFile = _storage.getFile(templatePath + ".vmdk"); + if (!srcFile.exists()) { + return new CopyCmdAnswer("Can't find src file:" + templatePath); + } } } } diff --git a/services/secondary-storage/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java b/services/secondary-storage/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java index c01537ce230..84daf27de7c 100755 --- a/services/secondary-storage/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java +++ b/services/secondary-storage/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java @@ -75,6 +75,7 @@ import com.cloud.storage.template.TemplateDownloader.Status; import com.cloud.storage.template.TemplateLocation; import com.cloud.storage.template.TemplateProp; import com.cloud.storage.template.VhdProcessor; +import com.cloud.storage.template.OVAProcessor; import com.cloud.storage.template.VmdkProcessor; import com.cloud.utils.NumbersUtil; import com.cloud.utils.component.ManagerBase; @@ -840,8 +841,8 @@ public class DownloadManagerImpl extends ManagerBase implements DownloadManager if ((tInfo.getSize() == tInfo.getPhysicalSize()) && (tInfo.getInstallPath().endsWith(ImageFormat.OVA.getFileExtension()))) { try { - Processor processor = _processors.get("VMDK Processor"); - VmdkProcessor vmdkProcessor = (VmdkProcessor)processor; + Processor processor = _processors.get("OVA Processor"); + OVAProcessor vmdkProcessor = (OVAProcessor)processor; long vSize = vmdkProcessor.getTemplateVirtualSize(path, tInfo.getInstallPath().substring(tInfo.getInstallPath().lastIndexOf(File.separator) + 1)); tInfo.setSize(vSize); loc.updateVirtualSize(vSize); @@ -897,8 +898,8 @@ public class DownloadManagerImpl extends ManagerBase implements DownloadManager if ((vInfo.getSize() == vInfo.getPhysicalSize()) && (vInfo.getInstallPath().endsWith(ImageFormat.OVA.getFileExtension()))) { try { - Processor processor = _processors.get("VMDK Processor"); - VmdkProcessor vmdkProcessor = (VmdkProcessor)processor; + Processor processor = _processors.get("OVA Processor"); + OVAProcessor vmdkProcessor = (OVAProcessor)processor; long vSize = vmdkProcessor.getTemplateVirtualSize(path, vInfo.getInstallPath().substring(vInfo.getInstallPath().lastIndexOf(File.separator) + 1)); vInfo.setSize(vSize); loc.updateVirtualSize(vSize); @@ -1052,6 +1053,10 @@ public class DownloadManagerImpl extends ManagerBase implements DownloadManager processor.configure("QCOW2 Processor", params); _processors.put("QCOW2 Processor", processor); + processor = new OVAProcessor(); + processor.configure("OVA Processor", params); + _processors.put("OVA Processor", processor); + processor = new VmdkProcessor(); processor.configure("VMDK Processor", params); _processors.put("VMDK Processor", processor); diff --git a/ui/scripts/templates.js b/ui/scripts/templates.js index bcceb89cf85..3854db77759 100644 --- a/ui/scripts/templates.js +++ b/ui/scripts/templates.js @@ -361,6 +361,18 @@ id: 'QCOW2', description: 'QCOW2' }); + items.push({ + id: 'RAW', + description: 'RAW' + }); + items.push({ + id: 'VHD', + description: 'VHD' + }); + items.push({ + id: 'VMDK', + description: 'VMDK' + }); } else if (args.hypervisor == "BareMetal") { //formatSelect.append(""); items.push({