diff --git a/core/src/com/cloud/server/ManagementServer.java b/core/src/com/cloud/server/ManagementServer.java index 024cba0f4cf..3aeb78ba48e 100644 --- a/core/src/com/cloud/server/ManagementServer.java +++ b/core/src/com/cloud/server/ManagementServer.java @@ -2177,5 +2177,8 @@ public interface ManagementServer { public List getPreAllocatedLuns(Criteria c); public String getNetworkGroupsNamesForVm(long vmId); + SnapshotVO createTemplateSnapshot(Long userId, long volumeId); + boolean destroyTemplateSnapshot(Long userId, long snapshotId); + String getHyperType(); } diff --git a/server/src/com/cloud/async/executor/CreatePrivateTemplateExecutor.java b/server/src/com/cloud/async/executor/CreatePrivateTemplateExecutor.java index cd73537cce1..acdb8844287 100644 --- a/server/src/com/cloud/async/executor/CreatePrivateTemplateExecutor.java +++ b/server/src/com/cloud/async/executor/CreatePrivateTemplateExecutor.java @@ -116,11 +116,10 @@ public class CreatePrivateTemplateExecutor extends VolumeOperationExecutor { asyncMgr.updateAsyncJobStatus(job.getId(), BaseCmd.PROGRESS_INSTANCE_CREATED, template.getId()); Snapshot snapshot = null; - if (snapshotId == null) { + if (snapshotId == null && managerServer.getHyperType().equalsIgnoreCase("KVM")) { // We are create private template from volume. Create a snapshot, copy the vhd chain of the disk to secondary storage. // For template snapshot, we use a separate snapshot method. - //snapshot = vmMgr.createTemplateSnapshot(param.getUserId(), param.getVolumeId()); - throw new CloudRuntimeException("Do not support create template from volume at this moment"); + snapshot = vmMgr.createTemplateSnapshot(param.getUserId(), param.getVolumeId()); } else { // We are creating a private template from an already present snapshot. diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 3ce7e892f21..4fba1c03b02 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -105,6 +105,7 @@ import com.cloud.async.executor.VolumeOperationParam; import com.cloud.async.executor.VolumeOperationParam.VolumeOp; import com.cloud.capacity.CapacityVO; import com.cloud.capacity.dao.CapacityDao; +import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManager; import com.cloud.configuration.ConfigurationVO; import com.cloud.configuration.ResourceCount.ResourceType; @@ -6341,6 +6342,22 @@ public class ManagementServerImpl implements ManagementServer { return jobId; } + + @Override + public SnapshotVO createTemplateSnapshot(Long userId, long volumeId) { + return _vmMgr.createTemplateSnapshot(userId, volumeId); + } + + @Override + public boolean destroyTemplateSnapshot(Long userId, long snapshotId) { + return _vmMgr.destroyTemplateSnapshot(userId, snapshotId); + } + + @Override + public String getHyperType() { + return _configDao.getValue(Config.HypervisorType.key()); + } + @Override public long deleteSnapshotAsync(long userId, long snapshotId) { Snapshot snapshot = findSnapshotById(snapshotId); diff --git a/server/src/com/cloud/vm/UserVmManager.java b/server/src/com/cloud/vm/UserVmManager.java index 2dc8c52894e..81b165ab9ab 100644 --- a/server/src/com/cloud/vm/UserVmManager.java +++ b/server/src/com/cloud/vm/UserVmManager.java @@ -209,5 +209,9 @@ public interface UserVmManager extends Manager, VirtualMachineManager */ void releaseGuestIpAddress(UserVmVO userVm); + boolean destroyTemplateSnapshot(Long userId, long snapshotId); + + SnapshotVO createTemplateSnapshot(long userId, long volumeId); + } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index cadc71ec47b..0a1fac8c4de 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -2029,6 +2029,87 @@ public class UserVmManagerImpl implements UserVmManager { } } + @Override + public boolean destroyTemplateSnapshot(Long userId, long snapshotId) { + boolean success = false; + SnapshotVO snapshot = _snapshotDao.findById(Long.valueOf(snapshotId)); + if (snapshot != null) { + VolumeVO volume = _volsDao.findById(snapshot.getVolumeId()); + ManageSnapshotCommand cmd = new ManageSnapshotCommand(ManageSnapshotCommand.DESTROY_SNAPSHOT, snapshotId, snapshot.getPath(), null, snapshot.getName()); + + Answer answer = null; + String basicErrMsg = "Failed to destroy template snapshot: " + snapshot.getName(); + Long storagePoolId = volume.getPoolId(); + answer = _storageMgr.sendToHostsOnStoragePool(storagePoolId, cmd, basicErrMsg); + + if ((answer != null) && answer.getResult()) { + // delete the snapshot from the database + _snapshotDao.delete(snapshotId); + success = true; + } + if (answer != null) { + s_logger.error(answer.getDetails()); + } + } + + return success; + } + + + @Override @DB + public SnapshotVO createTemplateSnapshot(long userId, long volumeId) { + SnapshotVO createdSnapshot = null; + VolumeVO volume = _volsDao.findById(volumeId); + + Long id = null; + + // Determine the name for this snapshot + String timeString = DateUtil.getDateDisplayString(DateUtil.GMT_TIMEZONE, new Date(), DateUtil.YYYYMMDD_FORMAT); + String snapshotName = volume.getName() + "_" + timeString; + // Create the Snapshot object and save it so we can return it to the user + SnapshotType snapshotType = SnapshotType.TEMPLATE; + SnapshotVO snapshot = new SnapshotVO(volume.getAccountId(), volume.getId(), null, snapshotName, (short)snapshotType.ordinal(), snapshotType.name()); + snapshot = _snapshotDao.persist(snapshot); + id = snapshot.getId(); + + // Send a ManageSnapshotCommand to the agent + ManageSnapshotCommand cmd = new ManageSnapshotCommand(ManageSnapshotCommand.CREATE_SNAPSHOT, id, volume.getPath(), null, snapshotName); + + String basicErrMsg = "Failed to create snapshot for volume: " + volume.getId(); + // This can be sent to a KVM host too. We are only taking snapshots on primary storage, which doesn't require XenServer. + // So shouldBeSnapshotCapable is set to false. + ManageSnapshotAnswer answer = (ManageSnapshotAnswer) _storageMgr.sendToHostsOnStoragePool(volume.getPoolId(), cmd, basicErrMsg); + + // Update the snapshot in the database + if ((answer != null) && answer.getResult()) { + // The snapshot was successfully created + + Transaction txn = Transaction.currentTxn(); + txn.start(); + createdSnapshot = _snapshotDao.findById(id); + createdSnapshot.setPath(answer.getSnapshotPath()); + createdSnapshot.setStatus(Snapshot.Status.CreatedOnPrimary); + _snapshotDao.update(id, createdSnapshot); + txn.commit(); + + // Don't Create an event for Template Snapshots for now. + } else { + if (answer != null) { + s_logger.error(answer.getDetails()); + } + // The snapshot was not successfully created + Transaction txn = Transaction.currentTxn(); + txn.start(); + createdSnapshot = _snapshotDao.findById(id); + _snapshotDao.delete(id); + txn.commit(); + + createdSnapshot = null; + } + + return createdSnapshot; + } + @Override public void cleanNetworkRules(long userId, long instanceId) {