From 879a954b98bc071054770fd8625c4f4cc3e0c10c Mon Sep 17 00:00:00 2001 From: Edison Su Date: Tue, 14 May 2013 21:57:07 -0700 Subject: [PATCH] delete snapshot at the backend --- .../com/cloud/agent/api/SnapshotCommand.java | 4 +- .../storage/resource/StorageProcessor.java | 3 +- .../StorageSubsystemCommandHandlerBase.java | 2 + .../MockLocalNfsSecondaryStorageResource.java | 3 + .../storage/test/MockLocalHostEndPoint.java | 20 ++++ .../cloudstack/storage/test/SnapshotTest.java | 95 +++++++++++++------ .../storage/snapshot/SnapshotServiceImpl.java | 37 +++++++- .../snapshot/XenserverSnapshotStrategy.java | 5 +- .../cloudstack/storage/LocalHostEndpoint.java | 2 +- .../kvm/storage/KVMStorageProcessor.java | 6 ++ .../resource/VmwareStorageProcessor.java | 13 +++ .../resource/XenServerStorageProcessor.java | 30 ++++++ .../CloudStackImageStoreDriverImpl.java | 86 +++++++---------- .../cloud/template/TemplateManagerImpl.java | 9 ++ .../resource/NfsSecondaryStorageResource.java | 22 +++-- 15 files changed, 242 insertions(+), 95 deletions(-) create mode 100644 engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockLocalHostEndPoint.java diff --git a/core/src/com/cloud/agent/api/SnapshotCommand.java b/core/src/com/cloud/agent/api/SnapshotCommand.java index d8abeb62371..ccf9613d5e8 100644 --- a/core/src/com/cloud/agent/api/SnapshotCommand.java +++ b/core/src/com/cloud/agent/api/SnapshotCommand.java @@ -53,8 +53,8 @@ public class SnapshotCommand extends Command { public SnapshotCommand(StoragePool pool, String secondaryStorageUrl, String snapshotUuid, String snapshotName, Long dcId, Long accountId, Long volumeId) { - this.primaryStoragePoolNameLabel = pool.getUuid(); - this.primaryPool = new StorageFilerTO(pool); + // this.primaryStoragePoolNameLabel = pool.getUuid(); + //this.primaryPool = new StorageFilerTO(pool); this.snapshotUuid = snapshotUuid; this.secondaryStorageUrl = secondaryStorageUrl; this.dcId = dcId; diff --git a/core/src/com/cloud/storage/resource/StorageProcessor.java b/core/src/com/cloud/storage/resource/StorageProcessor.java index 86bfe4b92b9..ca441edcb79 100644 --- a/core/src/com/cloud/storage/resource/StorageProcessor.java +++ b/core/src/com/cloud/storage/resource/StorageProcessor.java @@ -25,8 +25,6 @@ import org.apache.cloudstack.storage.command.DeleteCommand; import org.apache.cloudstack.storage.command.DettachCommand; import com.cloud.agent.api.Answer; -import com.cloud.agent.api.to.DataTO; -import com.cloud.agent.api.to.DiskTO; public interface StorageProcessor { public Answer copyTemplateToPrimaryStorage(CopyCommand cmd); @@ -43,4 +41,5 @@ public interface StorageProcessor { public Answer createSnapshot(CreateObjectCommand cmd); public Answer deleteVolume(DeleteCommand cmd); public Answer createVolumeFromSnapshot(CopyCommand cmd); + public Answer deleteSnapshot(DeleteCommand cmd); } diff --git a/core/src/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java b/core/src/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java index d167d61867b..23ccd318253 100644 --- a/core/src/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java +++ b/core/src/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java @@ -110,6 +110,8 @@ public class StorageSubsystemCommandHandlerBase implements StorageSubsystemComma Answer answer = null; if (data.getObjectType() == DataObjectType.VOLUME) { answer = processor.deleteVolume(cmd); + } else if (data.getObjectType() == DataObjectType.SNAPSHOT) { + answer = processor.deleteSnapshot(cmd); } else { answer = new Answer(cmd, false, "unsupported type"); } diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/MockLocalNfsSecondaryStorageResource.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/MockLocalNfsSecondaryStorageResource.java index 6087bd21fc7..61c09dbfa30 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/MockLocalNfsSecondaryStorageResource.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/MockLocalNfsSecondaryStorageResource.java @@ -51,6 +51,7 @@ import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.utils.S3Utils; import com.cloud.utils.UriUtils; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.script.Script; @Component public class MockLocalNfsSecondaryStorageResource extends @@ -67,6 +68,8 @@ public class MockLocalNfsSecondaryStorageResource extends // TODO Auto-generated catch block e.printStackTrace(); } + + createTemplateFromSnapshotXenScript = Script.findScript(getDefaultScriptsDir(), "create_privatetemplate_from_snapshot_xen.sh"); /* _storage = new JavaStorageLayer(); diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockLocalHostEndPoint.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockLocalHostEndPoint.java new file mode 100644 index 00000000000..31901e24d6b --- /dev/null +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockLocalHostEndPoint.java @@ -0,0 +1,20 @@ +package org.apache.cloudstack.storage.test; + +import org.apache.cloudstack.storage.LocalHostEndpoint; +import org.apache.cloudstack.storage.command.CopyCommand; +import org.apache.cloudstack.storage.command.DownloadCommand; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.Command; +import com.cloud.agent.api.DeleteSnapshotBackupCommand; + +public class MockLocalHostEndPoint extends LocalHostEndpoint { + @Override + public Answer sendMessage(Command cmd) { + if ((cmd instanceof CopyCommand) || (cmd instanceof DownloadCommand) || (cmd instanceof DeleteSnapshotBackupCommand)) { + return resource.executeRequest(cmd); + } + // TODO Auto-generated method stub + return new Answer(cmd, false, "unsupported command:" + cmd.toString()); + } +} diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTest.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTest.java index 264db68eefb..2739b45eabd 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTest.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTest.java @@ -156,6 +156,7 @@ public class SnapshotTest extends CloudStackTestNGBase { long primaryStoreId; VMTemplateVO image; String imageStoreName = "testImageStore"; + RemoteHostEndPoint remoteEp; @Test(priority = -1) public void setUp() { ComponentContext.initComponentsLifeCycle(); @@ -250,6 +251,7 @@ public class SnapshotTest extends CloudStackTestNGBase { TemplateObjectTO to = new TemplateObjectTO(); to.setPath(this.getImageInstallPath()); to.setFormat(ImageFormat.VHD); + to.setSize(1000L); CopyCmdAnswer answer = new CopyCmdAnswer(to); templateOnStore.processEvent(Event.CreateOnlyRequested); templateOnStore.processEvent(Event.OperationSuccessed, answer); @@ -263,10 +265,10 @@ public class SnapshotTest extends CloudStackTestNGBase { hosts.add(this.host); Mockito.when(resourceMgr.listAllUpAndEnabledHosts((Type) Mockito.any(), Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong())).thenReturn(hosts); - RemoteHostEndPoint ep = RemoteHostEndPoint.getHypervisorHostEndPoint(this.host.getId(), this.host.getPrivateIpAddress()); - Mockito.when(epSelector.select(Mockito.any(DataObject.class), Mockito.any(DataObject.class))).thenReturn(ep); - Mockito.when(epSelector.select(Mockito.any(DataObject.class))).thenReturn(ep); - Mockito.when(epSelector.select(Mockito.any(DataStore.class))).thenReturn(ep); + remoteEp = RemoteHostEndPoint.getHypervisorHostEndPoint(this.host.getId(), this.host.getPrivateIpAddress()); + Mockito.when(epSelector.select(Mockito.any(DataObject.class), Mockito.any(DataObject.class))).thenReturn(remoteEp); + Mockito.when(epSelector.select(Mockito.any(DataObject.class))).thenReturn(remoteEp); + Mockito.when(epSelector.select(Mockito.any(DataStore.class))).thenReturn(remoteEp); Mockito.when(hyGuruMgr.getGuruProcessedCommandTargetHost(Mockito.anyLong(), Mockito.any(Command.class))).thenReturn(this.host.getId()); } @@ -360,20 +362,35 @@ public class SnapshotTest extends CloudStackTestNGBase { return null; } - //@Test + @Test public void createSnapshot() { VolumeInfo vol = createCopyBaseImage(); SnapshotVO snapshotVO = createSnapshotInDb(vol); SnapshotInfo snapshot = this.snapshotFactory.getSnapshot(snapshotVO.getId(), vol.getDataStore()); + SnapshotInfo newSnapshot = null; for (SnapshotStrategy strategy : this.snapshotStrategies) { if (strategy.canHandle(snapshot)) { - strategy.takeSnapshot(snapshot); + newSnapshot = strategy.takeSnapshot(snapshot); } } + AssertJUnit.assertNotNull(newSnapshot); + + LocalHostEndpoint ep = new MockLocalHostEndPoint(); + ep.setResource(new MockLocalNfsSecondaryStorageResource()); + Mockito.when(epSelector.select(Mockito.any(DataStore.class))).thenReturn(ep); + + //delete snapshot + for (SnapshotStrategy strategy : this.snapshotStrategies) { + if (strategy.canHandle(snapshot)) { + strategy.deleteSnapshot(newSnapshot.getId()); + } + } + + Mockito.when(epSelector.select(Mockito.any(DataStore.class))).thenReturn(remoteEp); } private VMTemplateVO createTemplateInDb() { - image = new VMTemplateVO(); + VMTemplateVO image = new VMTemplateVO(); image.setTemplateType(TemplateType.USER); image.setUniqueName(UUID.randomUUID().toString()); @@ -393,8 +410,50 @@ public class SnapshotTest extends CloudStackTestNGBase { image = imageDataDao.persist(image); return image; } + + @Test + public void createVolumeFromSnapshot() { + VolumeInfo vol = createCopyBaseImage(); + SnapshotVO snapshotVO = createSnapshotInDb(vol); + SnapshotInfo snapshot = this.snapshotFactory.getSnapshot(snapshotVO.getId(), vol.getDataStore()); + boolean result = false; + for (SnapshotStrategy strategy : this.snapshotStrategies) { + if (strategy.canHandle(snapshot)) { + snapshot = strategy.takeSnapshot(snapshot); + result = true; + } + } - //@Test + AssertJUnit.assertTrue(result); + + VolumeVO volVO = createVolume(vol.getTemplateId(), vol.getPoolId()); + VolumeInfo newVol = this.volFactory.getVolume(volVO.getId()); + this.volumeService.createVolumeFromSnapshot(newVol, newVol.getDataStore(), snapshot); + } + + @Test + public void deleteSnapshot() { + VolumeInfo vol = createCopyBaseImage(); + SnapshotVO snapshotVO = createSnapshotInDb(vol); + SnapshotInfo snapshot = this.snapshotFactory.getSnapshot(snapshotVO.getId(), vol.getDataStore()); + SnapshotInfo newSnapshot = null; + for (SnapshotStrategy strategy : this.snapshotStrategies) { + if (strategy.canHandle(snapshot)) { + newSnapshot = strategy.takeSnapshot(snapshot); + } + } + AssertJUnit.assertNotNull(newSnapshot); + + //create another snapshot + for (SnapshotStrategy strategy : this.snapshotStrategies) { + if (strategy.canHandle(snapshot)) { + strategy.deleteSnapshot(newSnapshot.getId()); + } + } + + } + + @Test public void createTemplateFromSnapshot() { VolumeInfo vol = createCopyBaseImage(); SnapshotVO snapshotVO = createSnapshotInDb(vol); @@ -417,23 +476,5 @@ public class SnapshotTest extends CloudStackTestNGBase { this.imageService.createTemplateFromSnapshotAsync(snapshot, tmpl, imageStore); } - @Test - public void createVolumeFromSnapshot() { - VolumeInfo vol = createCopyBaseImage(); - SnapshotVO snapshotVO = createSnapshotInDb(vol); - SnapshotInfo snapshot = this.snapshotFactory.getSnapshot(snapshotVO.getId(), vol.getDataStore()); - boolean result = false; - for (SnapshotStrategy strategy : this.snapshotStrategies) { - if (strategy.canHandle(snapshot)) { - snapshot = strategy.takeSnapshot(snapshot); - result = true; - } - } - - AssertJUnit.assertTrue(result); - - VolumeVO volVO = createVolume(vol.getTemplateId(), vol.getPoolId()); - VolumeInfo newVol = this.volFactory.getVolume(volVO.getId()); - this.volumeService.createVolumeFromSnapshot(newVol, newVol.getDataStore(), snapshot); - } + } diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java index 12d80576c85..fa6d558f532 100644 --- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java +++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java @@ -299,6 +299,9 @@ public class SnapshotServiceImpl implements SnapshotService { try { SnapshotResult res = future.get(); + if (res.isFailed()) { + throw new CloudRuntimeException(res.getResult()); + } SnapshotInfo destSnapshot = res.getSnashot(); return destSnapshot; } catch (InterruptedException e) { @@ -319,6 +322,12 @@ public class SnapshotServiceImpl implements SnapshotService { AsyncCallFuture future = context.future; SnapshotResult snapResult = new SnapshotResult(destSnapshot, result.getAnswer()); if (result.isFailed()) { + try { + destSnapshot.processEvent(Event.OperationFailed); + srcSnapshot.processEvent(Snapshot.Event.OperationFailed); + } catch (NoTransitionException e) { + s_logger.debug("Failed to update state: " + e.toString()); + } snapResult.setResult(result.getResult()); future.complete(snapResult); return null; @@ -397,7 +406,33 @@ public class SnapshotServiceImpl implements SnapshotService { @Override public boolean deleteSnapshot(SnapshotInfo snapInfo) { - return true; + snapInfo.processEvent(ObjectInDataStoreStateMachine.Event.DestroyRequested); + + AsyncCallFuture future = new AsyncCallFuture(); + DeleteSnapshotContext context = new DeleteSnapshotContext(null, + snapInfo, future); + AsyncCallbackDispatcher caller = AsyncCallbackDispatcher + .create(this); + caller.setCallback( + caller.getTarget().deleteSnapshotCallback(null, null)) + .setContext(context); + DataStore store = snapInfo.getDataStore(); + store.getDriver().deleteAsync(snapInfo, caller); + + SnapshotResult result = null; + try { + result = future.get(); + if (result.isFailed()) { + throw new CloudRuntimeException(result.getResult()); + } + return true; + } catch (InterruptedException e) { + s_logger.debug("delete snapshot is failed: " + e.toString()); + } catch (ExecutionException e) { + s_logger.debug("delete snapshot is failed: " + e.toString()); + } + + return false; } diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java index 072d14bf07a..32504eeaed5 100644 --- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java +++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java @@ -139,7 +139,7 @@ public class XenserverSnapshotStrategy extends SnapshotStrategyBase { SnapshotInfo child = snapshot.getChild(); SnapshotInfo parent = snapshot.getParent(); if (child == null) { - if (!parent.getPath().equalsIgnoreCase(snapshot.getPath())) { + if (parent == null || !parent.getPath().equalsIgnoreCase(snapshot.getPath())) { this.snapshotSvr.deleteSnapshot(snapshot); snapshot = parent; continue; @@ -178,9 +178,10 @@ public class XenserverSnapshotStrategy extends SnapshotStrategyBase { } try { + /* if (snapshotOnPrimary != null) { deleteSnapshotChain(snapshotOnPrimary); - } + }*/ SnapshotInfo snapshotOnImage = this.snapshotDataFactory.getSnapshot(snapshotId, DataStoreRole.Image); if (snapshotOnImage != null) { diff --git a/engine/storage/src/org/apache/cloudstack/storage/LocalHostEndpoint.java b/engine/storage/src/org/apache/cloudstack/storage/LocalHostEndpoint.java index 525a507a30b..3267de8eef8 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/LocalHostEndpoint.java +++ b/engine/storage/src/org/apache/cloudstack/storage/LocalHostEndpoint.java @@ -36,7 +36,7 @@ import com.cloud.storage.download.DownloadListener; public class LocalHostEndpoint implements EndPoint { private ScheduledExecutorService executor; - ServerResource resource; + protected ServerResource resource; public LocalHostEndpoint() { resource = new LocalNfsSecondaryStorageResource(); executor = Executors.newScheduledThreadPool(10); 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 c3fa12bbf3e..53a9308a3ac 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 @@ -409,6 +409,8 @@ public class KVMStorageProcessor implements StorageProcessor { TemplateObjectTO newTemplate = new TemplateObjectTO(); newTemplate.setPath(templateFolder + File.separator + templateName + ".qcow2"); + newTemplate.setSize(info.virtualSize); + newTemplate.setFormat(ImageFormat.QCOW2); return new CopyCmdAnswer(newTemplate); } catch (Exception e) { s_logger.debug("Failed to create template from volume: " + e.toString()); @@ -902,4 +904,8 @@ public class KVMStorageProcessor implements StorageProcessor { } } + @Override + public Answer deleteSnapshot(DeleteCommand cmd) { + return new Answer(cmd); + } } 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 16bfaf536b3..d3df0f59ce9 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java @@ -69,6 +69,7 @@ import com.cloud.hypervisor.vmware.resource.VmwareResource; import com.cloud.hypervisor.vmware.util.VmwareContext; import com.cloud.hypervisor.vmware.util.VmwareHelper; import com.cloud.serializer.GsonHelper; +import com.cloud.storage.DataStoreRole; import com.cloud.storage.JavaStorageLayer; import com.cloud.storage.StorageLayer; import com.cloud.storage.Volume; @@ -579,6 +580,7 @@ public class VmwareStorageProcessor implements StorageProcessor { TemplateObjectTO newTemplate = new TemplateObjectTO(); newTemplate.setPath(template.getName()); newTemplate.setFormat(ImageFormat.OVA); + newTemplate.setSize(result.third()); return new CopyCmdAnswer(newTemplate); } catch (Throwable e) { @@ -1272,4 +1274,15 @@ public class VmwareStorageProcessor implements StorageProcessor { } return new CopyCmdAnswer(details); } + + @Override + public Answer deleteSnapshot(DeleteCommand cmd) { + SnapshotObjectTO snapshot = (SnapshotObjectTO)cmd.getData(); + DataStoreTO store = snapshot.getDataStore(); + if (store.getRole() == DataStoreRole.Primary) { + return new Answer(cmd); + } else { + return new Answer(cmd, false, "unsupported command"); + } + } } 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 0ef35195a00..bdc3d30542f 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 @@ -66,6 +66,7 @@ import com.cloud.agent.api.to.StorageFilerTO; import com.cloud.agent.api.to.SwiftTO; import com.cloud.exception.InternalErrorException; import com.cloud.hypervisor.xen.resource.CitrixResourceBase.SRType; +import com.cloud.storage.DataStoreRole; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.resource.StorageProcessor; @@ -1389,6 +1390,7 @@ public class XenServerStorageProcessor implements StorageProcessor { TemplateObjectTO newTemplate = new TemplateObjectTO(); newTemplate.setPath(installPath); newTemplate.setFormat(ImageFormat.VHD); + newTemplate.setSize(virtualSize); CopyCmdAnswer answer = new CopyCmdAnswer(newTemplate); return answer; } catch (Exception e) { @@ -1470,4 +1472,32 @@ public class XenServerStorageProcessor implements StorageProcessor { // In all cases return something. return new CopyCmdAnswer(details); } + + @Override + public Answer deleteSnapshot(DeleteCommand cmd) { + SnapshotObjectTO snapshot = (SnapshotObjectTO)cmd.getData(); + DataStoreTO store = snapshot.getDataStore(); + if (store.getRole() == DataStoreRole.Primary) { + Connection conn = this.hypervisorResource.getConnection(); + VDI snapshotVdi = getVDIbyUuid(conn, snapshot.getPath()); + if (snapshotVdi == null) { + return new Answer(null); + } + String errMsg = null; + try { + this.deleteVDI(conn, snapshotVdi); + } catch (BadServerResponse e) { + s_logger.debug("delete snapshot failed:" + e.toString()); + errMsg = e.toString(); + } catch (XenAPIException e) { + s_logger.debug("delete snapshot failed:" + e.toString()); + errMsg = e.toString(); + } catch (XmlRpcException e) { + s_logger.debug("delete snapshot failed:" + e.toString()); + errMsg = e.toString(); + } + return new Answer(cmd, false, errMsg); + } + return new Answer(cmd, false, "unsupported storage type"); + } } diff --git a/plugins/storage/image/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackImageStoreDriverImpl.java b/plugins/storage/image/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackImageStoreDriverImpl.java index 6ebdb693209..0c46d5e2ea7 100644 --- a/plugins/storage/image/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackImageStoreDriverImpl.java +++ b/plugins/storage/image/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackImageStoreDriverImpl.java @@ -48,6 +48,7 @@ import org.apache.cloudstack.storage.snapshot.SnapshotObject; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; +import com.cloud.agent.api.DeleteSnapshotBackupCommand; import com.cloud.agent.api.storage.DeleteTemplateCommand; import com.cloud.agent.api.storage.DeleteVolumeCommand; import com.cloud.agent.api.storage.DownloadAnswer; @@ -101,8 +102,6 @@ public class CloudStackImageStoreDriverImpl implements ImageStoreDriver { @Inject private S3Manager _s3Mgr; @Inject AccountDao _accountDao; - @Inject UserVmDao _userVmDao; - @Inject UserVmJoinDao _userVmJoinDao; @Inject SecondaryStorageVmManager _ssvmMgr; @Inject @@ -280,46 +279,37 @@ public class CloudStackImageStoreDriverImpl implements ImageStoreDriver { UsageEventUtils.publishUsageEvent(eventType, account.getId(), sZoneId, templateId, null, null, null); - List userVmUsingIso = _userVmJoinDao.listActiveByIsoId(templateId); - // check if there is any VM using this ISO. - if (userVmUsingIso == null || userVmUsingIso.isEmpty()) { - // get installpath of this template on image store - TemplateDataStoreVO tmplStore = _templateStoreDao.findByStoreTemplate(storeId, templateId); - String installPath = tmplStore.getInstallPath(); - if (installPath != null) { - DeleteTemplateCommand cmd = new DeleteTemplateCommand(store.getTO(), installPath, template.getId(), template.getAccountId()); - EndPoint ep = _epSelector.select(templateObj); - Answer answer = ep.sendMessage(cmd); + // get installpath of this template on image store + TemplateDataStoreVO tmplStore = _templateStoreDao.findByStoreTemplate(storeId, templateId); + String installPath = tmplStore.getInstallPath(); + if (installPath != null) { + DeleteTemplateCommand cmd = new DeleteTemplateCommand(store.getTO(), installPath, template.getId(), template.getAccountId()); + EndPoint ep = _epSelector.select(templateObj); + Answer answer = ep.sendMessage(cmd); - if (answer == null || !answer.getResult()) { - s_logger.debug("Failed to deleted template at store: " + store.getName()); - CommandResult result = new CommandResult(); - result.setSuccess(false); - result.setResult("Delete template failed"); - callback.complete(result); + if (answer == null || !answer.getResult()) { + s_logger.debug("Failed to deleted template at store: " + store.getName()); + CommandResult result = new CommandResult(); + result.setSuccess(false); + result.setResult("Delete template failed"); + callback.complete(result); - } else { - s_logger.debug("Deleted template at: " + installPath); - CommandResult result = new CommandResult(); - result.setSuccess(true); - callback.complete(result); - } + } else { + s_logger.debug("Deleted template at: " + installPath); + CommandResult result = new CommandResult(); + result.setSuccess(true); + callback.complete(result); + } - List templateZones = templateZoneDao.listByZoneTemplate(sZoneId, templateId); - if (templateZones != null) { - for (VMTemplateZoneVO templateZone : templateZones) { - templateZoneDao.remove(templateZone.getId()); - } - } - } - } else{ - // cannot delete iso due to some VMs are using this - s_logger.debug("Cannot delete iso since some user vms are referencing it"); - CommandResult result = new CommandResult(); - result.setResult("Cannot delete iso since some user vms are referencing it"); - callback.complete(result); + List templateZones = templateZoneDao.listByZoneTemplate(sZoneId, templateId); + if (templateZones != null) { + for (VMTemplateZoneVO templateZone : templateZones) { + templateZoneDao.remove(templateZone.getId()); + } + } } + } private void deleteSnapshot(DataObject data, AsyncCompletionCallback callback) { @@ -336,29 +326,17 @@ public class CloudStackImageStoreDriverImpl implements ImageStoreDriver { } try { - /*String secondaryStoragePoolUrl = secStore.getUri(); - Long dcId = snapshot.getDataCenterId(); - Long accountId = snapshot.getAccountId(); - Long volumeId = snapshot.getVolumeId(); - - String backupOfSnapshot = snapshotObj; - if (backupOfSnapshot == null) { - callback.complete(result); - return; - } + String secondaryStoragePoolUrl = secStore.getUri(); DeleteSnapshotBackupCommand cmd = new DeleteSnapshotBackupCommand( - secStore.getTO(), secondaryStoragePoolUrl, dcId, accountId, volumeId, - backupOfSnapshot, false); + secStore.getTO(), secondaryStoragePoolUrl, null, null, null, + snapshotObj.getPath(), false); EndPoint ep = _epSelector.select(secStore); Answer answer = ep.sendMessage(cmd); - if ((answer != null) && answer.getResult()) { - snapshot.setBackupSnapshotId(null); - snapshotDao.update(snapshotObj.getId(), snapshot); - } else if (answer != null) { + if (answer != null && !answer.getResult()) { result.setResult(answer.getDetails()); - }*/ + } } catch (Exception e) { s_logger.debug("failed to delete snapshot: " + snapshotObj.getId() + ": " + e.toString()); result.setResult(e.toString()); diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java b/server/src/com/cloud/template/TemplateManagerImpl.java index 922cc3412d8..7fee53c1271 100755 --- a/server/src/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/com/cloud/template/TemplateManagerImpl.java @@ -88,6 +88,8 @@ import com.cloud.agent.api.storage.DestroyCommand; import com.cloud.agent.api.to.DataTO; import com.cloud.agent.api.to.DiskTO; import com.cloud.api.ApiDBUtils; +import com.cloud.api.query.dao.UserVmJoinDao; +import com.cloud.api.query.vo.UserVmJoinVO; import com.cloud.async.AsyncJobManager; import com.cloud.async.AsyncJobVO; import com.cloud.configuration.Config; @@ -253,6 +255,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, @Inject VolumeManager _volumeMgr; @Inject ImageStoreDao _imageStoreDao; @Inject EndPointSelector _epSelector; + @Inject UserVmJoinDao _userVmJoinDao; @Inject ConfigurationServer _configServer; @@ -1122,6 +1125,12 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, if (template.getFormat() != ImageFormat.ISO) { throw new InvalidParameterValueException("Please specify a valid iso."); } + + List userVmUsingIso = _userVmJoinDao.listActiveByIsoId(templateId); + // check if there is any VM using this ISO. + if (!userVmUsingIso.isEmpty()) { + throw new InvalidParameterValueException("Unable to delete iso, as it's used by other vms"); + } if (zoneId != null && (this._dataStoreMgr.getImageStore(zoneId) == null)) { throw new InvalidParameterValueException("Failed to find a secondary storage store in the specified zone."); 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 c93b99a1f11..93241760f3e 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 @@ -45,6 +45,7 @@ import javax.naming.ConfigurationException; import org.apache.cloudstack.storage.command.CopyCmdAnswer; import org.apache.cloudstack.storage.command.CopyCommand; +import org.apache.cloudstack.storage.command.DeleteCommand; import org.apache.cloudstack.storage.command.DownloadCommand; import org.apache.cloudstack.storage.command.DownloadProgressCommand; import org.apache.cloudstack.storage.template.DownloadManager; @@ -161,7 +162,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S protected String _parent = "/mnt/SecStorage"; final private String _tmpltDir = "/var/cloudstack/template"; final private String _tmpltpp = "template.properties"; - private String createTemplateFromSnapshotXenScript; + protected String createTemplateFromSnapshotXenScript; @Override public void disconnected() { @@ -223,7 +224,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S return Answer.createUnsupportedCommandAnswer(cmd); } } - + protected Answer copyFromS3ToNfs(CopyCommand cmd, DataTO srcData, S3TO s3, DataTO destData, NfsTO destImageStore) { final String storagePath = destImageStore.getUrl(); final String destPath = destData.getPath(); @@ -353,7 +354,11 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S command.add("-s", snapshotName); command.add("-n", templateName); command.add("-t", destPath); - command.execute(); + String result = command.execute(); + + if (result != null && !result.equalsIgnoreCase("")) { + return new CopyCmdAnswer(result); + } Map params = new HashMap(); params.put(StorageLayer.InstanceConfigKey, _storage); @@ -1109,9 +1114,14 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S private String deleteSnapshotBackupFromLocalFileSystem(final String secondaryStorageUrl, final Long accountId, final Long volumeId, final String name, final Boolean deleteAllFlag) { - - final String lPath = determineSnapshotLocalDirectory(secondaryStorageUrl, accountId, volumeId) + File.pathSeparator - + (deleteAllFlag ? "*" : "*" + name + "*"); + String lPath = null; + int index = name.lastIndexOf(File.separator); + String snapshotPath = name.substring(0, index); + if (deleteAllFlag) { + lPath = this.getRootDir(secondaryStorageUrl) + File.separator + snapshotPath + File.separator + "*"; + } else { + lPath = this.getRootDir(secondaryStorageUrl) + File.separator + name + "*"; + } final String result = deleteLocalFile(lPath);