diff --git a/api/src/com/cloud/agent/api/to/DatadiskTemplateTO.java b/api/src/com/cloud/agent/api/to/DatadiskTO.java similarity index 68% rename from api/src/com/cloud/agent/api/to/DatadiskTemplateTO.java rename to api/src/com/cloud/agent/api/to/DatadiskTO.java index 34d72375c99..514ca98f467 100644 --- a/api/src/com/cloud/agent/api/to/DatadiskTemplateTO.java +++ b/api/src/com/cloud/agent/api/to/DatadiskTO.java @@ -18,38 +18,20 @@ */ package com.cloud.agent.api.to; -public class DatadiskTemplateTO { - private long id; - private String uniqueName; +public class DatadiskTO { private String path; - private Long virtualSize; - private Long fileSize; + private long virtualSize; + private long fileSize; + boolean bootable; - public DatadiskTemplateTO() { + public DatadiskTO() { } - public DatadiskTemplateTO(long id, String uniqueName, String path, Long virtualSize, Long fileSize) { - this.id = id; - this.uniqueName = uniqueName; + public DatadiskTO(String path, long virtualSize, long fileSize, boolean bootable) { this.path = path; this.virtualSize = virtualSize; this.fileSize = fileSize; - } - - public long getId() { - return id; - } - - public void setId(long id) { - this.id = id; - } - - public String getUniqueName() { - return uniqueName; - } - - public void setUniqueName(String uniqueName) { - this.uniqueName = uniqueName; + this.bootable = bootable; } public String getPath() { @@ -71,4 +53,8 @@ public class DatadiskTemplateTO { public Long getFileSize() { return fileSize; } + + public boolean isBootable() { + return bootable; + } } diff --git a/core/src/com/cloud/agent/api/storage/CreateDatadiskTemplateCommand.java b/core/src/com/cloud/agent/api/storage/CreateDatadiskTemplateCommand.java index bd3843be2eb..548cc4559fa 100644 --- a/core/src/com/cloud/agent/api/storage/CreateDatadiskTemplateCommand.java +++ b/core/src/com/cloud/agent/api/storage/CreateDatadiskTemplateCommand.java @@ -23,12 +23,14 @@ public final class CreateDatadiskTemplateCommand extends Command { private DataTO dataDiskTemplate; private String path; private long fileSize; + private boolean bootable; - public CreateDatadiskTemplateCommand(DataTO dataDiskTemplate, String path, long fileSize) { + public CreateDatadiskTemplateCommand(DataTO dataDiskTemplate, String path, long fileSize, boolean bootable) { super(); this.dataDiskTemplate = dataDiskTemplate; this.path = path; this.fileSize = fileSize; + this.bootable = bootable; } protected CreateDatadiskTemplateCommand() { @@ -51,4 +53,8 @@ public final class CreateDatadiskTemplateCommand extends Command { public long getFileSize() { return fileSize; } + + public boolean getBootable() { + return bootable; + } } diff --git a/core/src/com/cloud/agent/api/storage/GetDatadisksAnswer.java b/core/src/com/cloud/agent/api/storage/GetDatadisksAnswer.java index ffcf26f6b26..58922175c55 100644 --- a/core/src/com/cloud/agent/api/storage/GetDatadisksAnswer.java +++ b/core/src/com/cloud/agent/api/storage/GetDatadisksAnswer.java @@ -20,17 +20,17 @@ import java.util.ArrayList; import java.util.List; import com.cloud.agent.api.Answer; -import com.cloud.utils.Ternary; +import com.cloud.agent.api.to.DatadiskTO; public class GetDatadisksAnswer extends Answer { - List> dataDiskDetails = new ArrayList>(); + List dataDiskDetails = new ArrayList(); - public GetDatadisksAnswer(List> dataDiskDetails) { + public GetDatadisksAnswer(List dataDiskDetails) { super(null); this.dataDiskDetails = dataDiskDetails; } - public List> getDataDiskDetails() { + public List getDataDiskDetails() { return dataDiskDetails; } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/TemplateService.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/TemplateService.java index ff045bcd0ba..b416e9dfb99 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/TemplateService.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/TemplateService.java @@ -18,15 +18,12 @@ */ package org.apache.cloudstack.engine.subsystem.api.storage; -import java.util.List; - import org.apache.cloudstack.framework.async.AsyncCallFuture; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.storage.command.CommandResult; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.StoragePool; -import com.cloud.utils.Ternary; public interface TemplateService { @@ -69,7 +66,5 @@ public interface TemplateService { void associateCrosszoneTemplatesToZone(long dcId); - List> getDatadiskTemplates(TemplateInfo template); - - AsyncCallFuture createDatadiskTemplateAsync(TemplateInfo parentTemplate, TemplateInfo dataDiskTemplate, String path, long fileSize); + AsyncCallFuture createDatadiskTemplateAsync(TemplateInfo parentTemplate, TemplateInfo dataDiskTemplate, String path, long fileSize, boolean bootable); } diff --git a/engine/api/src/org/apache/cloudstack/storage/image/datastore/ImageStoreEntity.java b/engine/api/src/org/apache/cloudstack/storage/image/datastore/ImageStoreEntity.java index be419b43a71..223fc4d5657 100644 --- a/engine/api/src/org/apache/cloudstack/storage/image/datastore/ImageStoreEntity.java +++ b/engine/api/src/org/apache/cloudstack/storage/image/datastore/ImageStoreEntity.java @@ -29,9 +29,9 @@ import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; +import com.cloud.agent.api.to.DatadiskTO; import com.cloud.storage.ImageStore; import com.cloud.storage.Storage.ImageFormat; -import com.cloud.utils.Ternary; public interface ImageStoreEntity extends DataStore, ImageStore { TemplateInfo getTemplate(long templateId); @@ -48,7 +48,7 @@ public interface ImageStoreEntity extends DataStore, ImageStore { String createEntityExtractUrl(String installPath, ImageFormat format, DataObject dataObject); // get the entity download URL - List> getDatadiskTemplates(DataObject obj); + List getDatadiskTemplates(DataObject obj); - Void createDataDiskTemplateAsync(TemplateInfo dataDiskTemplate, String path, long fileSize, AsyncCompletionCallback callback); + Void createDataDiskTemplateAsync(TemplateInfo dataDiskTemplate, String path, long fileSize, boolean bootable, AsyncCompletionCallback callback); } diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java index ffdfcba519d..c539dabcd18 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java @@ -67,14 +67,17 @@ import org.apache.cloudstack.storage.to.TemplateObjectTO; import com.cloud.agent.api.Answer; import com.cloud.agent.api.storage.ListTemplateAnswer; import com.cloud.agent.api.storage.ListTemplateCommand; +import com.cloud.agent.api.to.DatadiskTO; import com.cloud.alert.AlertManager; import com.cloud.configuration.Config; +import com.cloud.configuration.Resource.ResourceType; import com.cloud.dc.DataCenterVO; import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.exception.ResourceAllocationException; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.DataStoreRole; +import com.cloud.storage.ScopeType; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.TemplateType; import com.cloud.storage.StoragePool; @@ -91,9 +94,11 @@ import com.cloud.template.TemplateManager; import com.cloud.user.Account; import com.cloud.user.AccountManager; import com.cloud.user.ResourceLimitService; -import com.cloud.utils.Ternary; import com.cloud.utils.UriUtils; import com.cloud.utils.db.GlobalLock; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.TransactionCallbackNoReturn; +import com.cloud.utils.db.TransactionStatus; import com.cloud.utils.exception.CloudRuntimeException; @Component @@ -581,6 +586,18 @@ public class TemplateServiceImpl implements TemplateService { return null; } + // Check if OVA contains additional data disks. If yes, create Datadisk templates for each of the additional datadisk present in the OVA + if (template.getFormat().equals(ImageFormat.OVA)) { + if(!createDataDiskTemplates(template)) { + template.processEvent(ObjectInDataStoreStateMachine.Event.OperationFailed); + result.setResult(callbackResult.getResult()); + if (parentCallback != null) { + parentCallback.complete(result); + } + return null; + } + } + try { template.processEvent(ObjectInDataStoreStateMachine.Event.OperationSuccessed); } catch (Exception e) { @@ -597,6 +614,81 @@ public class TemplateServiceImpl implements TemplateService { return null; } + protected boolean createDataDiskTemplates(TemplateInfo parentTemplate) { + TemplateApiResult result = null; + // Get Datadisk template (if any) for OVA + List dataDiskTemplates = new ArrayList(); + ImageStoreEntity tmpltStore = (ImageStoreEntity)parentTemplate.getDataStore(); + dataDiskTemplates = tmpltStore.getDatadiskTemplates(parentTemplate); + s_logger.error("Found " + dataDiskTemplates.size() + " Datadisk template(s) for template: " + parentTemplate.getId()); + int diskCount = 1; + VMTemplateVO template = _templateDao.findById(parentTemplate.getId()); + DataStore imageStore = parentTemplate.getDataStore(); + for (DatadiskTO dataDiskTemplate : dataDiskTemplates) { + if (dataDiskTemplate.isBootable()) + continue; + // Make an entry in vm_template table + final long templateId = _templateDao.getNextInSequence(Long.class, "id"); + VMTemplateVO templateVO = new VMTemplateVO(templateId, template.getName() + "-DataDiskTemplate-" + diskCount, template.getFormat(), false, false, false, + TemplateType.DATADISK, template.getUrl(), template.requiresHvm(), template.getBits(), template.getAccountId(), null, + template.getDisplayText() + "-DataDiskTemplate", false, 0, false, template.getHypervisorType(), null, null, false, false); + templateVO.setParentTemplateId(template.getId()); + templateVO.setSize(dataDiskTemplate.getVirtualSize()); + templateVO = _templateDao.persist(templateVO); + // Make sync call to create Datadisk templates in image store + TemplateInfo dataDiskTemplateInfo = imageFactory.getTemplate(templateVO.getId(), imageStore); + AsyncCallFuture future = createDatadiskTemplateAsync(parentTemplate, dataDiskTemplateInfo, dataDiskTemplate.getPath(), + dataDiskTemplate.getFileSize(), dataDiskTemplate.isBootable()); + try { + result = future.get(); + if (result.isSuccess()) { + // Make an entry in template_zone_ref table + if (imageStore.getScope().getScopeType() == ScopeType.REGION) { + associateTemplateToZone(templateId, null); + } else if (imageStore.getScope().getScopeType() == ScopeType.ZONE) { + Long zoneId = ((ImageStoreEntity)imageStore).getDataCenterId(); + VMTemplateZoneVO templateZone = new VMTemplateZoneVO(zoneId, templateId, new Date()); + _vmTemplateZoneDao.persist(templateZone); + } + _resourceLimitMgr.incrementResourceCount(template.getAccountId(), ResourceType.secondary_storage, templateVO.getSize()); + } else { + // Cleanup Datadisk template enries in case of failure + Transaction.execute(new TransactionCallbackNoReturn() { + @Override + public void doInTransactionWithoutResult(TransactionStatus status) { + _vmTemplateStoreDao.deletePrimaryRecordsForTemplate(templateId); + _vmTemplateZoneDao.deletePrimaryRecordsForTemplate(templateId); + _templateDao.expunge(templateId); + } + }); + // Don't create the remaining Datadisk templates if creation of any of the Datadisk template failed + s_logger.error("Creation of Datadisk: " + templateVO.getId() + " failed: " + result.getResult()); + return false; + } + } catch (Exception e) { + s_logger.error("Creation of Datadisk: " + templateVO.getId() + " failed: " + result.getResult()); + return false; + } + diskCount++; + } + // Create disk template for the bootable parent template + for (DatadiskTO dataDiskTemplate : dataDiskTemplates) { + if (dataDiskTemplate.isBootable()) { + TemplateInfo templateInfo = imageFactory.getTemplate(template.getId(), imageStore); + AsyncCallFuture templateFuture = createDatadiskTemplateAsync(parentTemplate, templateInfo, dataDiskTemplate.getPath(), + dataDiskTemplate.getFileSize(), dataDiskTemplate.isBootable()); + try { + result = templateFuture.get(); + return result.isSuccess(); + } catch (Exception e) { + s_logger.error("Creation of template: " + template.getId() + " failed: " + result.getResult()); + return false; + } + } + } + return true; + } + @Override public AsyncCallFuture deleteTemplateAsync(TemplateInfo template) { TemplateObject to = (TemplateObject)template; @@ -891,14 +983,6 @@ public class TemplateServiceImpl implements TemplateService { } } - @Override - public List> getDatadiskTemplates(TemplateInfo template) { - List> dataDiskDetails = new ArrayList>(); - ImageStoreEntity tmpltStore = (ImageStoreEntity)template.getDataStore(); - dataDiskDetails = tmpltStore.getDatadiskTemplates(template); - return dataDiskDetails; - } - private class CreateDataDiskTemplateContext extends AsyncRpcContext { private final DataObject dataDiskTemplate; private final AsyncCallFuture future; @@ -915,18 +999,23 @@ public class TemplateServiceImpl implements TemplateService { } @Override - public AsyncCallFuture createDatadiskTemplateAsync(TemplateInfo parentTemplate, TemplateInfo dataDiskTemplate, String path, long fileSize) { + public AsyncCallFuture createDatadiskTemplateAsync(TemplateInfo parentTemplate, TemplateInfo dataDiskTemplate, String path, long fileSize, boolean bootable) { AsyncCallFuture future = new AsyncCallFuture(); // Make an entry for Datadisk template in template_store_ref table DataStore store = parentTemplate.getDataStore(); - TemplateObject dataDiskTemplateOnStore = (TemplateObject)store.create(dataDiskTemplate); - dataDiskTemplateOnStore.processEvent(ObjectInDataStoreStateMachine.Event.CreateOnlyRequested); + TemplateObject dataDiskTemplateOnStore; + if (!bootable) { + dataDiskTemplateOnStore = (TemplateObject)store.create(dataDiskTemplate); + dataDiskTemplateOnStore.processEvent(ObjectInDataStoreStateMachine.Event.CreateOnlyRequested); + } else { + dataDiskTemplateOnStore = (TemplateObject) imageFactory.getTemplate(parentTemplate, store); + } try { CreateDataDiskTemplateContext context = new CreateDataDiskTemplateContext(null, dataDiskTemplateOnStore, future); AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); - caller.setCallback(caller.getTarget().createDataDiskTemplateCallback(null, null)).setContext(context); + caller.setCallback(caller.getTarget().createDatadiskTemplateCallback(null, null)).setContext(context); ImageStoreEntity tmpltStore = (ImageStoreEntity)parentTemplate.getDataStore(); - tmpltStore.createDataDiskTemplateAsync(dataDiskTemplate, path, fileSize, caller); + tmpltStore.createDataDiskTemplateAsync(dataDiskTemplate, path, fileSize, bootable, caller); } catch (CloudRuntimeException ex) { dataDiskTemplateOnStore.processEvent(ObjectInDataStoreStateMachine.Event.OperationFailed); TemplateApiResult result = new TemplateApiResult(dataDiskTemplate); @@ -938,7 +1027,7 @@ public class TemplateServiceImpl implements TemplateService { return future; } - protected Void createDataDiskTemplateCallback(AsyncCallbackDispatcher callback, CreateDataDiskTemplateContext context) { + protected Void createDatadiskTemplateCallback(AsyncCallbackDispatcher callback, CreateDataDiskTemplateContext context) { if (s_logger.isDebugEnabled()) { s_logger.debug("Performing create datadisk template cross callback after completion"); } @@ -954,10 +1043,10 @@ public class TemplateServiceImpl implements TemplateService { dataDiskTemplateResult.setResult(result.getResult()); } } catch (Exception e) { - s_logger.debug("Failed to process copy template cross zones callback", e); + s_logger.debug("Failed to process create datadisk template callback", e); dataDiskTemplateResult.setResult(e.toString()); } future.complete(dataDiskTemplateResult); return null; } -} +} \ No newline at end of file diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/ImageStoreImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/ImageStoreImpl.java index 0a3b7e80bd9..97f09d083c4 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/ImageStoreImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/ImageStoreImpl.java @@ -45,12 +45,12 @@ import org.apache.cloudstack.storage.image.ImageStoreDriver; import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity; import org.apache.cloudstack.storage.to.ImageStoreTO; +import com.cloud.agent.api.to.DatadiskTO; import com.cloud.agent.api.to.DataStoreTO; import com.cloud.capacity.dao.CapacityDao; import com.cloud.storage.DataStoreRole; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.dao.VMTemplateDao; -import com.cloud.utils.Ternary; import com.cloud.utils.component.ComponentContext; public class ImageStoreImpl implements ImageStoreEntity { @@ -208,13 +208,12 @@ public class ImageStoreImpl implements ImageStoreEntity { } @Override - public List> getDatadiskTemplates(DataObject obj) { + public List getDatadiskTemplates(DataObject obj) { return driver.getDatadiskTemplates(obj); } @Override - public Void createDataDiskTemplateAsync(TemplateInfo dataDiskTemplate, String path, long fileSize, AsyncCompletionCallback callback) { - return driver.createDataDiskTemplateAsync(dataDiskTemplate, path, fileSize, callback); - + public Void createDataDiskTemplateAsync(TemplateInfo dataDiskTemplate, String path, long fileSize, boolean bootable, AsyncCompletionCallback callback) { + return driver.createDataDiskTemplateAsync(dataDiskTemplate, path, bootable, fileSize, callback); } } diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java b/engine/storage/src/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java index 94366ef7067..b170c757984 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java @@ -54,6 +54,7 @@ import com.cloud.agent.api.storage.DownloadAnswer; import com.cloud.agent.api.storage.GetDatadisksAnswer; import com.cloud.agent.api.storage.GetDatadisksCommand; import com.cloud.agent.api.storage.Proxy; +import com.cloud.agent.api.to.DatadiskTO; import com.cloud.agent.api.to.DataObjectType; import com.cloud.agent.api.to.DataTO; import com.cloud.hypervisor.Hypervisor.HypervisorType; @@ -66,7 +67,6 @@ import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.download.DownloadMonitor; import com.cloud.user.ResourceLimitService; import com.cloud.user.dao.AccountDao; -import com.cloud.utils.Ternary; public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver { private static final Logger s_logger = Logger.getLogger(BaseImageStoreDriverImpl.class); @@ -293,8 +293,8 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver { } @Override - public List> getDatadiskTemplates(DataObject obj) { - List> dataDiskDetails = new ArrayList>(); + public List getDatadiskTemplates(DataObject obj) { + List dataDiskDetails = new ArrayList(); if (s_logger.isDebugEnabled()) { s_logger.debug("Get the data disks present in the OVA template"); } @@ -311,20 +311,20 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver { } if (answer != null && answer.getResult()) { GetDatadisksAnswer getDatadisksAnswer = (GetDatadisksAnswer)answer; - dataDiskDetails = getDatadisksAnswer.getDataDiskDetails(); // Details - Disk path, virtual size + dataDiskDetails = getDatadisksAnswer.getDataDiskDetails(); // Details - Disk path, virtual size, bootable } return dataDiskDetails; } @Override - public Void createDataDiskTemplateAsync(TemplateInfo dataDiskTemplate, String path, long fileSize, + public Void createDataDiskTemplateAsync(TemplateInfo dataDiskTemplate, String path, boolean bootable, long fileSize, AsyncCompletionCallback callback) { Answer answer = null; String errMsg = null; if (s_logger.isDebugEnabled()) { s_logger.debug("Create Datadisk template: " + dataDiskTemplate.getId()); } - CreateDatadiskTemplateCommand cmd = new CreateDatadiskTemplateCommand(dataDiskTemplate.getTO(), path, fileSize); + CreateDatadiskTemplateCommand cmd = new CreateDatadiskTemplateCommand(dataDiskTemplate.getTO(), path, fileSize, bootable); EndPoint ep = _defaultEpSelector.selectHypervisorHostByType(dataDiskTemplate.getDataStore().getScope(), HypervisorType.VMware); if (ep == null) { errMsg = "No remote endpoint to send command, check if host or ssvm is down?"; diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/ImageStoreDriver.java b/engine/storage/src/org/apache/cloudstack/storage/image/ImageStoreDriver.java index e4e94517001..a262c9b71fc 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/image/ImageStoreDriver.java +++ b/engine/storage/src/org/apache/cloudstack/storage/image/ImageStoreDriver.java @@ -27,13 +27,13 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; +import com.cloud.agent.api.to.DatadiskTO; import com.cloud.storage.Storage.ImageFormat; -import com.cloud.utils.Ternary; public interface ImageStoreDriver extends DataStoreDriver { String createEntityExtractUrl(DataStore store, String installPath, ImageFormat format, DataObject dataObject); - List> getDatadiskTemplates(DataObject obj); + List getDatadiskTemplates(DataObject obj); - Void createDataDiskTemplateAsync(TemplateInfo dataDiskTemplate, String path, long fileSize, AsyncCompletionCallback callback); + Void createDataDiskTemplateAsync(TemplateInfo dataDiskTemplate, String path, boolean bootable, long fileSize, AsyncCompletionCallback callback); } 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 9a3ce407a8b..b1001f8f4ed 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 @@ -68,6 +68,7 @@ import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand; import com.cloud.agent.api.to.DataObjectType; import com.cloud.agent.api.to.DataStoreTO; import com.cloud.agent.api.to.DataTO; +import com.cloud.agent.api.to.DatadiskTO; import com.cloud.agent.api.to.NfsTO; import com.cloud.agent.api.to.StorageFilerTO; import com.cloud.hypervisor.vmware.mo.CustomFieldConstants; @@ -550,7 +551,7 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager { @Override public Answer execute(VmwareHostService hostService, GetDatadisksCommand cmd) { - List> datDiskDetails = new ArrayList>(); + List disks = new ArrayList(); DataTO srcData = cmd.getData(); TemplateObjectTO template = (TemplateObjectTO)srcData; DataStoreTO srcStore = srcData.getDataStore(); @@ -603,22 +604,19 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager { s_logger.debug("Reading OVF " + ovfFilePath + " to retrive the number of disks present in OVA"); List> ovfVolumeDetails = HypervisorHostHelper.readOVF(hyperHost, ovfFilePath, datastoreMo); - // Get the virtual size of data disk + // Get OVA disk details for (Pair ovfVolumeDetail : ovfVolumeDetails) { - if (ovfVolumeDetail.second()) { // ROOT disk - continue; - } String dataDiskPath = ovfVolumeDetail.first(); String diskName = dataDiskPath.substring((dataDiskPath.lastIndexOf(File.separator)) + 1); Pair diskDetails = new OVAProcessor().getDiskDetails(ovfFilePath, diskName); - datDiskDetails.add(new Ternary(dataDiskPath, diskDetails.first(), diskDetails.second())); + disks.add(new DatadiskTO(dataDiskPath, diskDetails.first(), diskDetails.second(), ovfVolumeDetail.second())); } } catch (Exception e) { String msg = "Get Datadisk Template Count failed due to " + e.getMessage(); s_logger.error(msg); return new GetDatadisksAnswer(msg); } - return new GetDatadisksAnswer(datDiskDetails); + return new GetDatadisksAnswer(disks); } @Override @@ -653,36 +651,50 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager { long physicalSize = new File(dataDiskPath).length(); String dataDiskTemplateFolderPath = getTemplateRelativeDirInSecStorage(dataDiskTemplate.getAccountId(), dataDiskTemplate.getId()); String dataDiskTemplateFolderFullPath = secondaryMountPoint + "/" + dataDiskTemplateFolderPath; - - // Create folder to hold datadisk template - synchronized (dataDiskTemplateFolderPath.intern()) { - Script command = new Script(false, "mkdir", _timeout, s_logger); - command.add("-p"); - command.add(dataDiskTemplateFolderFullPath); - String result = command.execute(); - if (result != null) { - String msg = "Unable to prepare template directory: " + dataDiskTemplateFolderPath + ", storage: " + secondaryStorageUrl + ", error msg: " + result; - s_logger.error(msg); - throw new Exception(msg); - } - } - - // Copy Datadisk VMDK from parent template folder to Datadisk template folder - synchronized (dataDiskPath.intern()) { - Script command = new Script(false, "cp", _timeout, s_logger); - command.add(dataDiskPath); - command.add(dataDiskTemplateFolderFullPath); - String result = command.execute(); - if (result != null) { - String msg = "Unable to copy VMDK from parent template folder to datadisk template folder" + ", error msg: " + result; - s_logger.error(msg); - throw new Exception(msg); - } - } - String ovfName = diskName.substring(0, diskName.lastIndexOf("-")); String datastorePath = String.format("[%s] %s", datastoreMo.getName(), dataDiskTemplateFolderPath); + if (!cmd.getBootable()) { + // Create folder to hold datadisk template + synchronized (dataDiskTemplateFolderPath.intern()) { + Script command = new Script(false, "mkdir", _timeout, s_logger); + command.add("-p"); + command.add(dataDiskTemplateFolderFullPath); + String result = command.execute(); + if (result != null) { + String msg = "Unable to prepare template directory: " + dataDiskTemplateFolderPath + ", storage: " + secondaryStorageUrl + ", error msg: " + result; + s_logger.error(msg); + throw new Exception(msg); + } + } + // Move Datadisk VMDK from parent template folder to Datadisk template folder + synchronized (dataDiskPath.intern()) { + Script command = new Script(false, "mv", _timeout, s_logger); + command.add(dataDiskPath); + command.add(dataDiskTemplateFolderFullPath); + String result = command.execute(); + if (result != null) { + String msg = "Unable to copy VMDK from parent template folder to datadisk template folder" + ", error msg: " + result; + s_logger.error(msg); + throw new Exception(msg); + } + } + } else { + // Delete original OVA as a new OVA will be created for the root disk template + String rootDiskTemplatePath = dataDiskTemplate.getPath(); + String rootDiskTemplateFullPath = secondaryMountPoint + "/" + rootDiskTemplatePath; + synchronized (rootDiskTemplateFullPath.intern()) { + Script command = new Script(false, "rm", _timeout, s_logger); + command.add(rootDiskTemplateFullPath); + String result = command.execute(); + if (result != null) { + String msg = "Unable to delete original OVA" + ", error msg: " + result; + s_logger.error(msg); + throw new Exception(msg); + } + } + } + // Create OVF for Datadisk s_logger.debug("Creating OVF file for datadisk " + diskName + " in " + dataDiskTemplateFolderFullPath); HypervisorHostHelper.createOvfFile(hyperHost, diskName, ovfName, datastorePath, dataDiskTemplateFolderFullPath, virtualSize, fileSize, morDs); diff --git a/server/src/com/cloud/template/HypervisorTemplateAdapter.java b/server/src/com/cloud/template/HypervisorTemplateAdapter.java index f984872d6bc..8bef4a54ba2 100755 --- a/server/src/com/cloud/template/HypervisorTemplateAdapter.java +++ b/server/src/com/cloud/template/HypervisorTemplateAdapter.java @@ -19,7 +19,6 @@ package com.cloud.template; import java.net.MalformedURLException; import java.net.URL; import java.util.Collections; -import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -75,13 +74,9 @@ import com.cloud.storage.dao.VMTemplateZoneDao; import com.cloud.storage.download.DownloadMonitor; import com.cloud.user.Account; import com.cloud.utils.Pair; -import com.cloud.utils.Ternary; import com.cloud.utils.UriUtils; import com.cloud.utils.db.DB; import com.cloud.utils.db.EntityManager; -import com.cloud.utils.db.Transaction; -import com.cloud.utils.db.TransactionCallbackNoReturn; -import com.cloud.utils.db.TransactionStatus; import com.cloud.utils.exception.CloudRuntimeException; @Local(value = TemplateAdapter.class) @@ -301,10 +296,6 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase { TemplateInfo template = context.template; if (result.isSuccess()) { VMTemplateVO tmplt = _tmpltDao.findById(template.getId()); - // Check if OVA contains additional data disks. If yes, create Datadisk templates for each of the additional datadisk present in the OVA - if (template.getFormat().equals(ImageFormat.OVA)) { - createDataDiskTemplates(template); - } // need to grant permission for public templates if (tmplt.isPublicTemplate()) { _messageBus.publish(_name, TemplateManager.MESSAGE_REGISTER_PUBLIC_TEMPLATE_EVENT, PublishScope.LOCAL, tmplt.getId()); @@ -346,60 +337,6 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase { return null; } - private void createDataDiskTemplates(TemplateInfo parentTemplate) { - TemplateApiResult result = null; - VMTemplateVO template = _tmpltDao.findById(parentTemplate.getId()); - DataStore imageStore = parentTemplate.getDataStore(); - List> dataDiskTemplates = imageService.getDatadiskTemplates(parentTemplate); - s_logger.error("Found " + dataDiskTemplates.size() + " Datadisk templates for template: " + parentTemplate.getId()); - int diskCount = 1; - for (Ternary dataDiskTemplate : dataDiskTemplates) { - // Make an entry in vm_template table - final long templateId = _templateDao.getNextInSequence(Long.class, "id"); - VMTemplateVO templateVO = new VMTemplateVO(templateId, template.getName() + "-DataDiskTemplate-" + diskCount, template.getFormat(), false, false, false, - TemplateType.DATADISK, template.getUrl(), template.requiresHvm(), template.getBits(), template.getAccountId(), null, - template.getDisplayText() + "-DataDiskTemplate", false, 0, false, template.getHypervisorType(), null, null, false, false); - templateVO.setParentTemplateId(template.getId()); - templateVO.setSize(dataDiskTemplate.second()); - templateVO = _templateDao.persist(templateVO); - // Make sync call to create Datadisk templates in image store - TemplateInfo dataDiskTemplateInfo = imageFactory.getTemplate(templateVO.getId(), imageStore); - AsyncCallFuture future = imageService.createDatadiskTemplateAsync(parentTemplate, dataDiskTemplateInfo, dataDiskTemplate.first(), - dataDiskTemplate.third()); - try { - result = future.get(); - if (result.isSuccess()) { - // Make an entry in template_zone_ref table - if (imageStore.getScope().getScopeType() == ScopeType.REGION) { - imageService.associateTemplateToZone(templateId, null); - } else if (imageStore.getScope().getScopeType() == ScopeType.ZONE) { - Long zoneId = ((ImageStoreEntity)imageStore).getDataCenterId(); - VMTemplateZoneVO templateZone = new VMTemplateZoneVO(zoneId, templateId, new Date()); - _tmpltZoneDao.persist(templateZone); - } - _resourceLimitMgr.incrementResourceCount(template.getAccountId(), ResourceType.secondary_storage, templateVO.getSize()); - } else { - // Cleanup Datadisk template enries in case of failure - Transaction.execute(new TransactionCallbackNoReturn() { - @Override - public void doInTransactionWithoutResult(TransactionStatus status) { - _tmplStoreDao.deletePrimaryRecordsForTemplate(templateId); - _tmpltZoneDao.deletePrimaryRecordsForTemplate(templateId); - _tmpltDao.expunge(templateId); - } - }); - // Continue to create the remaining Datadisk templates even if creation of 1 Datadisk template failes - s_logger.error("Creation of Datadisk: " + templateVO.getId() + " failed: " + result.getResult()); - continue; - } - } catch (Exception e) { - s_logger.error("Creation of Datadisk: " + templateVO.getId() + " failed: " + result.getResult()); - continue; - } - diskCount++; - } - } - @Override @DB public boolean delete(TemplateProfile profile) { diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 9a0d2a1b290..8a719de857b 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -2612,18 +2612,24 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir (dataDiskTemplate.getState().equals(VirtualMachineTemplate.State.Active))) { throw new InvalidParameterValueException("Invalid template id specified for Datadisk template" + datadiskTemplateToDiskOffering.getKey()); } + long dataDiskTemplateId = datadiskTemplateToDiskOffering.getKey(); if (!dataDiskTemplate.getParentTemplateId().equals(template.getId())) { - throw new InvalidParameterValueException("Invalid Datadisk template. Specified Datadisk template " + datadiskTemplateToDiskOffering.getKey() + throw new InvalidParameterValueException("Invalid Datadisk template. Specified Datadisk template " + dataDiskTemplateId + " doesn't belong to template " + template.getId()); } if (dataDiskOffering == null) { - throw new InvalidParameterValueException("Invalid disk offering id specified" + datadiskTemplateToDiskOffering.getValue()); + throw new InvalidParameterValueException("Invalid disk offering id " + datadiskTemplateToDiskOffering.getValue().getId() + + " specified for datadisk template " + dataDiskTemplateId); + } + if (dataDiskOffering.isCustomized()) { + throw new InvalidParameterValueException("Invalid disk offering id " + dataDiskOffering.getId() + " specified for datadisk template " + + dataDiskTemplateId + ". Custom Disk offerings are not supported for Datadisk templates"); + } + if (dataDiskOffering.getDiskSize() < dataDiskTemplate.getSize()) { + throw new InvalidParameterValueException("Invalid disk offering id " + dataDiskOffering.getId() + " specified for datadisk template " + + dataDiskTemplateId + ". Disk offering size should be greater than or equal to the template size"); } _templateDao.loadDetails(dataDiskTemplate); - if (dataDiskOffering.isCustomized()) { - throw new InvalidParameterValueException("Invalid disk offering id specified" + datadiskTemplateToDiskOffering.getValue() + ". Custom Disk offerings are not" + - " supported for Datadisk templates"); - } _resourceLimitMgr.checkResourceLimit(owner, ResourceType.volume, 1); _resourceLimitMgr.checkResourceLimit(owner, ResourceType.primary_storage, dataDiskOffering.getDiskSize()); }