diff --git a/api/src/com/cloud/agent/api/to/DataTO.java b/api/src/com/cloud/agent/api/to/DataTO.java index 21e802fde1f..8d24a050057 100644 --- a/api/src/com/cloud/agent/api/to/DataTO.java +++ b/api/src/com/cloud/agent/api/to/DataTO.java @@ -18,9 +18,12 @@ */ package com.cloud.agent.api.to; +import com.cloud.hypervisor.Hypervisor; + public interface DataTO { public DataObjectType getObjectType(); public DataStoreTO getDataStore(); + public Hypervisor.HypervisorType getHypervisorType(); /** * @return */ diff --git a/api/src/com/cloud/hypervisor/HypervisorGuru.java b/api/src/com/cloud/hypervisor/HypervisorGuru.java index 47ca17a84a3..0d0fed82333 100644 --- a/api/src/com/cloud/hypervisor/HypervisorGuru.java +++ b/api/src/com/cloud/hypervisor/HypervisorGuru.java @@ -22,6 +22,7 @@ import com.cloud.agent.api.Command; import com.cloud.agent.api.to.NicTO; import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.utils.Pair; import com.cloud.utils.component.Adapter; import com.cloud.vm.NicProfile; import com.cloud.vm.VirtualMachine; @@ -40,12 +41,13 @@ public interface HypervisorGuru extends Adapter { /** * Give hypervisor guru opportunity to decide if certain command needs to be delegated to other host, mainly to secondary storage VM host + * * @param hostId original hypervisor host * @param cmd command that is going to be sent, hypervisor guru usually needs to register various context objects into the command object * * @return delegated host id if the command will be delegated */ - long getCommandHostDelegation(long hostId, Command cmd); + Pair getCommandHostDelegation(long hostId, Command cmd); /** * @return true if VM can be migrated independently with CloudStack, and therefore CloudStack needs to track and reflect host change diff --git a/core/src/com/cloud/storage/resource/StorageProcessor.java b/core/src/com/cloud/storage/resource/StorageProcessor.java index f503fa3889c..5fa9f8a86e3 100644 --- a/core/src/com/cloud/storage/resource/StorageProcessor.java +++ b/core/src/com/cloud/storage/resource/StorageProcessor.java @@ -32,6 +32,7 @@ public interface StorageProcessor { public Answer copyVolumeFromImageCacheToPrimary(CopyCommand cmd); public Answer copyVolumeFromPrimaryToSecondary(CopyCommand cmd); public Answer createTemplateFromVolume(CopyCommand cmd); + public Answer createTemplateFromSnapshot(CopyCommand cmd); public Answer backupSnapshot(CopyCommand cmd); public Answer attachIso(AttachCommand cmd); public Answer attachVolume(AttachCommand cmd); diff --git a/core/src/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java b/core/src/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java index c0bbfbea4d9..385a277757b 100644 --- a/core/src/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java +++ b/core/src/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java @@ -84,6 +84,8 @@ public class StorageSubsystemCommandHandlerBase implements StorageSubsystemComma return processor.backupSnapshot(cmd); } else if (srcData.getObjectType() == DataObjectType.SNAPSHOT && destData.getObjectType() == DataObjectType.VOLUME) { return processor.createVolumeFromSnapshot(cmd); + } else if (srcData.getObjectType() == DataObjectType.SNAPSHOT && destData.getObjectType() == DataObjectType.TEMPLATE) { + return processor.createTemplateFromSnapshot(cmd); } return new Answer(cmd, false, "not implemented yet"); diff --git a/engine/api/src/org/apache/cloudstack/storage/to/SnapshotObjectTO.java b/engine/api/src/org/apache/cloudstack/storage/to/SnapshotObjectTO.java index 4754dcf34e1..d2cb72a387c 100644 --- a/engine/api/src/org/apache/cloudstack/storage/to/SnapshotObjectTO.java +++ b/engine/api/src/org/apache/cloudstack/storage/to/SnapshotObjectTO.java @@ -111,6 +111,7 @@ public class SnapshotObjectTO implements DataTO { this.name = name; } + @Override public HypervisorType getHypervisorType() { return hypervisorType; } diff --git a/engine/api/src/org/apache/cloudstack/storage/to/TemplateObjectTO.java b/engine/api/src/org/apache/cloudstack/storage/to/TemplateObjectTO.java index abe59eb2b4d..2347de35168 100644 --- a/engine/api/src/org/apache/cloudstack/storage/to/TemplateObjectTO.java +++ b/engine/api/src/org/apache/cloudstack/storage/to/TemplateObjectTO.java @@ -16,6 +16,7 @@ // under the License. package org.apache.cloudstack.storage.to; +import com.cloud.hypervisor.Hypervisor; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import com.cloud.agent.api.to.DataObjectType; @@ -38,6 +39,7 @@ public class TemplateObjectTO implements DataTO { private String name; private String guestOsType; private Long size; + private Hypervisor.HypervisorType hypervisorType; public TemplateObjectTO() { @@ -53,6 +55,7 @@ public class TemplateObjectTO implements DataTO { this.accountId = template.getAccountId(); this.name = template.getUniqueName(); this.format = template.getFormat(); + this.hypervisorType = template.getHypervisorType(); } public TemplateObjectTO(TemplateInfo template) { @@ -69,6 +72,7 @@ public class TemplateObjectTO implements DataTO { if (template.getDataStore() != null) { this.imageDataStore = template.getDataStore().getTO(); } + this.hypervisorType = template.getHypervisorType(); } @Override @@ -128,6 +132,11 @@ public class TemplateObjectTO implements DataTO { return this.imageDataStore; } + @Override + public Hypervisor.HypervisorType getHypervisorType() { + return this.hypervisorType; + } + public void setDataStore(DataStoreTO store){ this.imageDataStore = store; } diff --git a/engine/api/src/org/apache/cloudstack/storage/to/VolumeObjectTO.java b/engine/api/src/org/apache/cloudstack/storage/to/VolumeObjectTO.java index ab3d5ea14d3..9f466ae4a10 100644 --- a/engine/api/src/org/apache/cloudstack/storage/to/VolumeObjectTO.java +++ b/engine/api/src/org/apache/cloudstack/storage/to/VolumeObjectTO.java @@ -16,6 +16,7 @@ // under the License. package org.apache.cloudstack.storage.to; +import com.cloud.hypervisor.Hypervisor; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import com.cloud.agent.api.to.DataObjectType; @@ -41,6 +42,7 @@ public class VolumeObjectTO implements DataTO { private Long bytesWriteRate; private Long iopsReadRate; private Long iopsWriteRate; + private Hypervisor.HypervisorType hypervisorType; public VolumeObjectTO() { @@ -67,6 +69,7 @@ public class VolumeObjectTO implements DataTO { this.bytesWriteRate = volume.getBytesWriteRate(); this.iopsReadRate = volume.getIopsReadRate(); this.iopsWriteRate = volume.getIopsWriteRate(); + this.hypervisorType = volume.getHypervisorType(); } public String getUuid() { @@ -87,6 +90,11 @@ public class VolumeObjectTO implements DataTO { return this.dataStore; } + @Override + public Hypervisor.HypervisorType getHypervisorType() { + return this.hypervisorType; + } + public void setDataStore(DataStoreTO store){ this.dataStore = store; 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 25c94f76c95..ea6460a5cbf 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 @@ -403,6 +403,11 @@ public class KVMStorageProcessor implements StorageProcessor { } } + @Override + public Answer createTemplateFromSnapshot(CopyCommand cmd) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + @Override public Answer backupSnapshot(CopyCommand cmd) { DataTO srcData = cmd.getSrcTO(); diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java index b86b6d97b6f..fa6831ef117 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java @@ -28,6 +28,7 @@ import java.util.UUID; import javax.ejb.Local; import javax.inject.Inject; +import com.cloud.host.Host; import org.apache.log4j.Logger; import org.apache.cloudstack.storage.command.CopyCommand; @@ -42,7 +43,6 @@ import com.cloud.agent.api.UnregisterVMCommand; import com.cloud.agent.api.storage.CopyVolumeCommand; import com.cloud.agent.api.storage.CreateVolumeOVACommand; import com.cloud.agent.api.storage.PrepareOVAPackingCommand; -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; @@ -294,92 +294,82 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru { } @Override @DB - public long getCommandHostDelegation(long hostId, Command cmd) { + public Pair getCommandHostDelegation(long hostId, Command cmd) { boolean needDelegation = false; - if(cmd instanceof PrimaryStorageDownloadCommand || - cmd instanceof BackupSnapshotCommand || - cmd instanceof CreatePrivateTemplateFromVolumeCommand || - cmd instanceof CreatePrivateTemplateFromSnapshotCommand || - cmd instanceof CopyVolumeCommand || - cmd instanceof CreateVolumeOVACommand || - cmd instanceof PrepareOVAPackingCommand || - cmd instanceof CreateVolumeFromSnapshotCommand || - cmd instanceof CopyCommand) { - if (cmd instanceof CopyCommand) { - CopyCommand cpyCommand = (CopyCommand)cmd; - DataTO srcData = cpyCommand.getSrcTO(); - DataStoreTO srcStoreTO = srcData.getDataStore(); - DataTO destData = cpyCommand.getDestTO(); - DataStoreTO destStoreTO = destData.getDataStore(); + if (cmd instanceof CopyCommand) { + CopyCommand cpyCommand = (CopyCommand)cmd; + DataTO srcData = cpyCommand.getSrcTO(); + DataStoreTO srcStoreTO = srcData.getDataStore(); + DataTO destData = cpyCommand.getDestTO(); + DataStoreTO destStoreTO = destData.getDataStore(); - if (destData.getObjectType() == DataObjectType.VOLUME && destStoreTO.getRole() == DataStoreRole.Primary && - srcData.getObjectType() == DataObjectType.TEMPLATE && srcStoreTO.getRole() == DataStoreRole.Primary) { - needDelegation = false; - } else { - needDelegation = true; - } + if (!(HypervisorType.VMware == srcData.getHypervisorType() || + HypervisorType.VMware == destData.getHypervisorType() + )) { + return new Pair(Boolean.FALSE, new Long(hostId)); + } + + if (destData.getObjectType() == DataObjectType.VOLUME && destStoreTO.getRole() == DataStoreRole.Primary && + srcData.getObjectType() == DataObjectType.TEMPLATE && srcStoreTO.getRole() == DataStoreRole.Primary) { + needDelegation = false; } else { needDelegation = true; } - } - /* Fang: remove this before checking in */ - // needDelegation = false; - if (cmd instanceof PrepareOVAPackingCommand || - cmd instanceof CreateVolumeOVACommand ) { + if(!needDelegation) { + return new Pair(Boolean.FALSE, new Long(hostId)); + } + + HostVO host = _hostDao.findById(hostId); + long dcId = host.getDataCenterId(); + + Pair cmdTarget = _secStorageMgr.assignSecStorageVm(dcId, cmd); + if(cmdTarget != null) { + // TODO, we need to make sure agent is actually connected too + cmd.setContextParam("hypervisor", HypervisorType.VMware.toString()); - } - if(needDelegation) { - HostVO host = _hostDao.findById(hostId); - assert(host != null); - assert(host.getHypervisorType() == HypervisorType.VMware); - long dcId = host.getDataCenterId(); - - Pair cmdTarget = _secStorageMgr.assignSecStorageVm(dcId, cmd); - if(cmdTarget != null) { - // TODO, we need to make sure agent is actually connected too - cmd.setContextParam("hypervisor", HypervisorType.VMware.toString()); + if (host.getType() == Host.Type.Routing) { Map hostDetails = _hostDetailsDao.findDetails(hostId); cmd.setContextParam("guid", resolveNameInGuid(hostDetails.get("guid"))); cmd.setContextParam("username", hostDetails.get("username")); cmd.setContextParam("password", hostDetails.get("password")); cmd.setContextParam("serviceconsole", _vmwareMgr.getServiceConsolePortGroupName()); cmd.setContextParam("manageportgroup", _vmwareMgr.getManagementPortGroupName()); - - CommandExecLogVO execLog = new CommandExecLogVO(cmdTarget.first().getId(), cmdTarget.second().getId(), cmd.getClass().getSimpleName(), 1); - _cmdExecLogDao.persist(execLog); - cmd.setContextParam("execid", String.valueOf(execLog.getId())); - - if(cmd instanceof BackupSnapshotCommand || - cmd instanceof CreatePrivateTemplateFromVolumeCommand || - cmd instanceof CreatePrivateTemplateFromSnapshotCommand || - cmd instanceof CopyVolumeCommand || - cmd instanceof CopyCommand || - cmd instanceof CreateVolumeOVACommand || - cmd instanceof PrepareOVAPackingCommand || - cmd instanceof CreateVolumeFromSnapshotCommand) { - - String workerName = _vmwareMgr.composeWorkerName(); - long checkPointId = 1; - // FIXME: Fix long checkPointId = _checkPointMgr.pushCheckPoint(new VmwareCleanupMaid(hostDetails.get("guid"), workerName)); - cmd.setContextParam("worker", workerName); - cmd.setContextParam("checkpoint", String.valueOf(checkPointId)); - - // some commands use 2 workers - String workerName2 = _vmwareMgr.composeWorkerName(); - long checkPointId2 = 1; - // FIXME: Fix long checkPointId2 = _checkPointMgr.pushCheckPoint(new VmwareCleanupMaid(hostDetails.get("guid"), workerName2)); - cmd.setContextParam("worker2", workerName2); - cmd.setContextParam("checkpoint2", String.valueOf(checkPointId2)); - } - - return cmdTarget.first().getId(); } - } - return hostId; + CommandExecLogVO execLog = new CommandExecLogVO(cmdTarget.first().getId(), cmdTarget.second().getId(), cmd.getClass().getSimpleName(), 1); + _cmdExecLogDao.persist(execLog); + cmd.setContextParam("execid", String.valueOf(execLog.getId())); + + if(cmd instanceof BackupSnapshotCommand || + cmd instanceof CreatePrivateTemplateFromVolumeCommand || + cmd instanceof CreatePrivateTemplateFromSnapshotCommand || + cmd instanceof CopyVolumeCommand || + cmd instanceof CopyCommand || + cmd instanceof CreateVolumeOVACommand || + cmd instanceof PrepareOVAPackingCommand || + cmd instanceof CreateVolumeFromSnapshotCommand) { + + String workerName = _vmwareMgr.composeWorkerName(); + long checkPointId = 1; + // FIXME: Fix long checkPointId = _checkPointMgr.pushCheckPoint(new VmwareCleanupMaid(hostDetails.get("guid"), workerName)); + cmd.setContextParam("worker", workerName); + cmd.setContextParam("checkpoint", String.valueOf(checkPointId)); + + // some commands use 2 workers + String workerName2 = _vmwareMgr.composeWorkerName(); + long checkPointId2 = 1; + // FIXME: Fix long checkPointId2 = _checkPointMgr.pushCheckPoint(new VmwareCleanupMaid(hostDetails.get("guid"), workerName2)); + cmd.setContextParam("worker2", workerName2); + cmd.setContextParam("checkpoint2", String.valueOf(checkPointId2)); + } + + return new Pair(Boolean.TRUE,cmdTarget.first().getId()); + + } + return new Pair(Boolean.FALSE, new Long(hostId)); } @Override 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 4760ac20cd3..ccf4e43b026 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java @@ -39,6 +39,7 @@ import org.apache.cloudstack.storage.to.PrimaryDataStoreTO; import org.apache.cloudstack.storage.to.SnapshotObjectTO; import org.apache.cloudstack.storage.to.TemplateObjectTO; import org.apache.cloudstack.storage.to.VolumeObjectTO; +import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import com.cloud.agent.api.Answer; @@ -77,7 +78,6 @@ import com.cloud.storage.Volume; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.template.VmdkProcessor; import com.cloud.utils.Pair; -import com.cloud.utils.StringUtils; import com.cloud.utils.Ternary; import com.cloud.utils.script.Script; import com.cloud.vm.VirtualMachine.State; @@ -543,7 +543,6 @@ public class VmwareStorageProcessor implements StorageProcessor { @Override public Answer createTemplateFromVolume(CopyCommand cmd) { VolumeObjectTO volume = (VolumeObjectTO)cmd.getSrcTO(); - PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)volume.getDataStore(); TemplateObjectTO template = (TemplateObjectTO)cmd.getDestTO(); DataStoreTO imageStore = template.getDataStore(); @@ -579,7 +578,7 @@ public class VmwareStorageProcessor implements StorageProcessor { hostService.getWorkerName(context, cmd, 0)); TemplateObjectTO newTemplate = new TemplateObjectTO(); - newTemplate.setPath(template.getName()); + newTemplate.setPath(result.first()); newTemplate.setFormat(ImageFormat.OVA); newTemplate.setSize(result.third()); return new CopyCmdAnswer(newTemplate); @@ -591,12 +590,196 @@ public class VmwareStorageProcessor implements StorageProcessor { s_logger.error("Unexpecpted exception ", e); - details = "CreatePrivateTemplateFromVolumeCommand exception: " + StringUtils.getExceptionStackInfo(e); + details = "CreatePrivateTemplateFromVolumeCommand exception: " + e.toString(); return new CopyCmdAnswer(details); } } - - private void exportVolumeToSecondaryStroage(VirtualMachineMO vmMo, String volumePath, + + private void writeMetaOvaForTemplate(String installFullPath, String ovfFilename, String vmdkFilename, + String templateName, long diskSize) throws Exception { + + // TODO a bit ugly here + BufferedWriter out = null; + try { + out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(installFullPath + "/" + templateName +".ova.meta"))); + out.write("ova.filename=" + templateName + ".ova"); + out.newLine(); + out.write("version=1.0"); + out.newLine(); + out.write("ovf=" + ovfFilename); + out.newLine(); + out.write("numDisks=1"); + out.newLine(); + out.write("disk1.name=" + vmdkFilename); + out.newLine(); + out.write("disk1.size=" + diskSize); + out.newLine(); + } finally { + if(out != null) + out.close(); + } + } + + private Ternary createTemplateFromSnapshot(String installPath, String templateUniqueName, + String secStorageUrl, String snapshotPath, Long templateId) throws Exception { + //Snapshot path is decoded in this form: /snapshots/account/volumeId/uuid/uuid + String[] tokens = snapshotPath.split(File.separator); + String backupSSUuid = tokens[tokens.length - 1]; + String snapshotFolder = StringUtils.join(tokens, File.separator, 0, tokens.length -1); + + String secondaryMountPoint = mountService.getMountPoint(secStorageUrl); + String installFullPath = secondaryMountPoint + "/" + installPath; + String installFullOVAName = installFullPath + "/" + templateUniqueName + ".ova"; //Note: volss for tmpl + String snapshotRoot = secondaryMountPoint + "/" + snapshotFolder; + String snapshotFullOVAName = snapshotRoot + "/" + backupSSUuid + ".ova"; + String snapshotFullOvfName = snapshotRoot + "/" + backupSSUuid + ".ovf"; + String result; + Script command; + String templateVMDKName = ""; + String snapshotFullVMDKName = snapshotRoot + "/" + backupSSUuid + "/"; + + synchronized(installPath.intern()) { + command = new Script(false, "mkdir", _timeout, s_logger); + command.add("-p"); + command.add(installFullPath); + + result = command.execute(); + if(result != null) { + String msg = "unable to prepare template directory: " + + installPath + ", storage: " + secStorageUrl + ", error msg: " + result; + s_logger.error(msg); + throw new Exception(msg); + } + } + + try { + if(new File(snapshotFullOVAName).exists()) { + command = new Script(false, "cp", _timeout, s_logger); + command.add(snapshotFullOVAName); + command.add(installFullOVAName); + result = command.execute(); + if(result != null) { + String msg = "unable to copy snapshot " + snapshotFullOVAName + " to " + installFullPath; + s_logger.error(msg); + throw new Exception(msg); + } + + // untar OVA file at template directory + command = new Script("tar", 0, s_logger); + command.add("--no-same-owner"); + command.add("-xf", installFullOVAName); + command.setWorkDir(installFullPath); + s_logger.info("Executing command: " + command.toString()); + result = command.execute(); + if(result != null) { + String msg = "unable to untar snapshot " + snapshotFullOVAName + " to " + + installFullPath; + s_logger.error(msg); + throw new Exception(msg); + } + + } else { // there is no ova file, only ovf originally; + if(new File(snapshotFullOvfName).exists()) { + command = new Script(false, "cp", _timeout, s_logger); + command.add(snapshotFullOvfName); + //command.add(installFullOvfName); + command.add(installFullPath); + result = command.execute(); + if(result != null) { + String msg = "unable to copy snapshot " + snapshotFullOvfName + " to " + installFullPath; + s_logger.error(msg); + throw new Exception(msg); + } + + s_logger.info("vmdkfile parent dir: " + snapshotFullVMDKName); + File snapshotdir = new File(snapshotFullVMDKName); + // File snapshotdir = new File(snapshotRoot); + File[] ssfiles = snapshotdir.listFiles(); + // List filenames = new ArrayList(); + for (int i = 0; i < ssfiles.length; i++) { + String vmdkfile = ssfiles[i].getName(); + s_logger.info("vmdk file name: " + vmdkfile); + if(vmdkfile.toLowerCase().startsWith(backupSSUuid) && vmdkfile.toLowerCase().endsWith(".vmdk")) { + snapshotFullVMDKName += vmdkfile; + templateVMDKName += vmdkfile; + break; + } + } + if (snapshotFullVMDKName != null) { + command = new Script(false, "cp", _timeout, s_logger); + command.add(snapshotFullVMDKName); + command.add(installFullPath); + result = command.execute(); + s_logger.info("Copy VMDK file: " + snapshotFullVMDKName); + if(result != null) { + String msg = "unable to copy snapshot vmdk file " + snapshotFullVMDKName + " to " + installFullPath; + s_logger.error(msg); + throw new Exception(msg); + } + } + } else { + String msg = "unable to find any snapshot ova/ovf files" + snapshotFullOVAName + " to " + installFullPath; + s_logger.error(msg); + throw new Exception(msg); + } + } + + long physicalSize = new File(installFullPath + "/" + templateVMDKName).length(); + VmdkProcessor processor = new VmdkProcessor(); + // long physicalSize = new File(installFullPath + "/" + templateUniqueName + ".ova").length(); + Map params = new HashMap(); + params.put(StorageLayer.InstanceConfigKey, _storage); + processor.configure("VMDK Processor", params); + long virtualSize = processor.getTemplateVirtualSize(installFullPath, templateUniqueName); + + postCreatePrivateTemplate(installFullPath, templateId, templateUniqueName, physicalSize, virtualSize); + writeMetaOvaForTemplate(installFullPath, backupSSUuid + File.separator + backupSSUuid + ".ovf", templateVMDKName, templateUniqueName, physicalSize); + return new Ternary(installPath + "/" + templateUniqueName + ".ova", physicalSize, virtualSize); + } catch(Exception e) { + // TODO, clean up left over files + throw e; + } + } + + @Override + public Answer createTemplateFromSnapshot(CopyCommand cmd) { + SnapshotObjectTO snapshot = (SnapshotObjectTO)cmd.getSrcTO(); + TemplateObjectTO template = (TemplateObjectTO)cmd.getDestTO(); + DataStoreTO imageStore = template.getDataStore(); + String details; + String uniqeName = UUID.randomUUID().toString(); + + VmwareContext context = hostService.getServiceContext(cmd); + try { + if (!(imageStore instanceof NfsTO)) { + return new CopyCmdAnswer("Only support create template from snapshot, when the dest store is nfs"); + } + + NfsTO nfsSvr = (NfsTO)imageStore; + Ternary result = createTemplateFromSnapshot(template.getPath(), + uniqeName, + nfsSvr.getUrl(), snapshot.getPath(), + template.getId() + ); + + TemplateObjectTO newTemplate = new TemplateObjectTO(); + newTemplate.setPath(result.first()); + newTemplate.setSize(result.second()); + newTemplate.setFormat(ImageFormat.OVA); + return new CopyCmdAnswer(newTemplate); + } catch (Throwable e) { + if (e instanceof RemoteException) { + hostService.invalidateServiceContext(context); + } + + s_logger.error("Unexpecpted exception ", e); + + details = "CreatePrivateTemplateFromSnapshotCommand exception: " + e.toString(); + return new CopyCmdAnswer(details); + } + } + + private void exportVolumeToSecondaryStroage(VirtualMachineMO vmMo, String volumePath, String secStorageUrl, String secStorageDir, String exportName, String workerVmName) throws Exception { @@ -760,7 +943,7 @@ public class VmwareStorageProcessor implements StorageProcessor { s_logger.error("Unexpecpted exception ", e); - details = "BackupSnapshotCommand exception: " + StringUtils.getExceptionStackInfo(e); + details = "BackupSnapshotCommand exception: " + e.toString(); return new CopyCmdAnswer(details); } } @@ -1298,7 +1481,7 @@ public class VmwareStorageProcessor implements StorageProcessor { } s_logger.error("Unexpecpted exception ", e); - details = "CreateVolumeFromSnapshotCommand exception: " + StringUtils.getExceptionStackInfo(e); + details = "CreateVolumeFromSnapshotCommand exception: " + e.toString(); } return new CopyCmdAnswer(details); } diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java index e88d6a52845..b7fdccacea0 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java @@ -1438,7 +1438,12 @@ public class XenServerStorageProcessor implements StorageProcessor { return new CopyCmdAnswer(details); } - @Override + @Override + public Answer createTemplateFromSnapshot(CopyCommand cmd) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override public Answer createVolumeFromSnapshot(CopyCommand cmd) { Connection conn = this.hypervisorResource.getConnection(); DataTO srcData = cmd.getSrcTO(); diff --git a/server/src/com/cloud/hypervisor/HypervisorGuruBase.java b/server/src/com/cloud/hypervisor/HypervisorGuruBase.java index 2ffd6821d3e..ec685290f38 100644 --- a/server/src/com/cloud/hypervisor/HypervisorGuruBase.java +++ b/server/src/com/cloud/hypervisor/HypervisorGuruBase.java @@ -29,6 +29,7 @@ import com.cloud.configuration.Config; import com.cloud.offering.ServiceOffering; import com.cloud.server.ConfigurationServer; import com.cloud.storage.dao.VMTemplateDetailsDao; +import com.cloud.utils.Pair; import com.cloud.utils.component.AdapterBase; import com.cloud.vm.NicProfile; import com.cloud.vm.NicVO; @@ -135,8 +136,8 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis } @Override - public long getCommandHostDelegation(long hostId, Command cmd) { - return hostId; + public Pair getCommandHostDelegation(long hostId, Command cmd) { + return new Pair(Boolean.FALSE, new Long(hostId)); } @Override diff --git a/server/src/com/cloud/hypervisor/HypervisorGuruManagerImpl.java b/server/src/com/cloud/hypervisor/HypervisorGuruManagerImpl.java index a8aad57abff..4d1e1b50b40 100644 --- a/server/src/com/cloud/hypervisor/HypervisorGuruManagerImpl.java +++ b/server/src/com/cloud/hypervisor/HypervisorGuruManagerImpl.java @@ -25,6 +25,7 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.utils.Pair; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -59,15 +60,12 @@ public class HypervisorGuruManagerImpl extends ManagerBase implements Hypervisor @Override public long getGuruProcessedCommandTargetHost(long hostId, Command cmd) { - HostVO hostVo = _hostDao.findById(hostId); - HypervisorGuru hvGuru = null; - if(hostVo.getType() == Host.Type.Routing) { - hvGuru = _hvGurus.get(hostVo.getHypervisorType()); + for(HypervisorGuru guru : _hvGuruList) { + Pair result = guru.getCommandHostDelegation(hostId, cmd); + if (result.first()) { + return result.second(); + } } - - if(hvGuru != null) - return hvGuru.getCommandHostDelegation(hostId, cmd); - return hostId; } }