You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ed...@apache.org on 2013/02/14 02:11:27 UTC
[15/50] [abbrv] CLOUDSTACK-684 support vm snapshot
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/9a12756a/api/src/org/apache/cloudstack/api/response/VMSnapshotResponse.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/response/VMSnapshotResponse.java b/api/src/org/apache/cloudstack/api/response/VMSnapshotResponse.java
new file mode 100644
index 0000000..3b30ab6
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/response/VMSnapshotResponse.java
@@ -0,0 +1,220 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.cloudstack.api.response;
+
+import java.util.Date;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseResponse;
+import org.apache.cloudstack.api.EntityReference;
+
+import com.cloud.serializer.Param;
+import com.cloud.vm.snapshot.VMSnapshot;
+import com.google.gson.annotations.SerializedName;
+
+@EntityReference(value=VMSnapshot.class)
+public class VMSnapshotResponse extends BaseResponse implements ControlledEntityResponse{
+
+ @SerializedName(ApiConstants.ID)
+ @Param(description = "the ID of the vm snapshot")
+ private String id;
+
+ @SerializedName(ApiConstants.NAME)
+ @Param(description = "the name of the vm snapshot")
+ private String name;
+
+ @SerializedName(ApiConstants.STATE)
+ @Param(description = "the state of the vm snapshot")
+ private VMSnapshot.State state;
+
+ @SerializedName(ApiConstants.DESCRIPTION)
+ @Param(description = "the description of the vm snapshot")
+ private String description;
+
+ @SerializedName(ApiConstants.DISPLAY_NAME)
+ @Param(description = "the display name of the vm snapshot")
+ private String displayName;
+
+ @SerializedName(ApiConstants.ZONE_ID)
+ @Param(description = "the Zone ID of the vm snapshot")
+ private String zoneId;
+
+ @SerializedName(ApiConstants.VIRTUAL_MACHINE_ID)
+ @Param(description = "the vm ID of the vm snapshot")
+ private String virtualMachineid;
+
+ @SerializedName("parent")
+ @Param(description = "the parent ID of the vm snapshot")
+ private String parent;
+
+ @SerializedName("parentName")
+ @Param(description = "the parent displayName of the vm snapshot")
+ private String parentName;
+
+ @SerializedName("current")
+ @Param(description = "indiates if this is current snapshot")
+ private Boolean current;
+
+ @SerializedName("type")
+ @Param(description = "VM Snapshot type")
+ private String type;
+
+ @SerializedName(ApiConstants.CREATED)
+ @Param(description = "the create date of the vm snapshot")
+ private Date created;
+
+ @SerializedName(ApiConstants.ACCOUNT)
+ @Param(description = "the account associated with the disk volume")
+ private String accountName;
+
+ @SerializedName(ApiConstants.PROJECT_ID) @Param(description="the project id of the vpn")
+ private String projectId;
+
+ @SerializedName(ApiConstants.PROJECT) @Param(description="the project name of the vpn")
+ private String projectName;
+
+ @SerializedName(ApiConstants.DOMAIN_ID)
+ @Param(description = "the ID of the domain associated with the disk volume")
+ private String domainId;
+
+ @SerializedName(ApiConstants.DOMAIN)
+ @Param(description = "the domain associated with the disk volume")
+ private String domainName;
+
+ @Override
+ public String getObjectId() {
+ return getId();
+ }
+
+ public Date getCreated() {
+ return created;
+ }
+
+ public void setCreated(Date created) {
+ this.created = created;
+ }
+
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ public void setDisplayName(String displayName) {
+ this.displayName = displayName;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getZoneId() {
+ return zoneId;
+ }
+
+ public void setZoneId(String zoneId) {
+ this.zoneId = zoneId;
+ }
+
+ public String getVirtualMachineid() {
+ return virtualMachineid;
+ }
+
+ public void setVirtualMachineid(String virtualMachineid) {
+ this.virtualMachineid = virtualMachineid;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setState(VMSnapshot.State state) {
+ this.state = state;
+ }
+
+ public VMSnapshot.State getState() {
+ return state;
+ }
+
+ public Boolean getCurrent() {
+ return current;
+ }
+
+ public void setCurrent(Boolean current) {
+ this.current = current;
+ }
+
+ public void setParentName(String parentName) {
+ this.parentName = parentName;
+ }
+
+ public String getParentName() {
+ return parentName;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ @Override
+ public void setAccountName(String accountName) {
+ this.accountName = accountName;
+
+ }
+
+ @Override
+ public void setProjectId(String projectId) {
+ this.projectId = projectId;
+
+ }
+
+ @Override
+ public void setProjectName(String projectName) {
+ this.projectName = projectName;
+
+ }
+
+ @Override
+ public void setDomainId(String domainId) {
+ this.domainId = domainId;
+ }
+
+ @Override
+ public void setDomainName(String domainName) {
+ this.domainName = domainName;
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/9a12756a/client/WEB-INF/classes/resources/messages.properties
----------------------------------------------------------------------
diff --git a/client/WEB-INF/classes/resources/messages.properties b/client/WEB-INF/classes/resources/messages.properties
index 9c4fcb3..11b1ca1 100644
--- a/client/WEB-INF/classes/resources/messages.properties
+++ b/client/WEB-INF/classes/resources/messages.properties
@@ -1410,6 +1410,20 @@ label.zone.step.4.title=Step 4: <strong>Add an IP range</strong>
label.zone.wide=Zone-Wide
label.zone=Zone
+#VM snapshot label
+label.vmsnapshot=VM Snapshots
+label.vmsnapshot.type=Type
+label.vmsnapshot.parentname=Parent
+label.vmsnapshot.current=isCurrent
+label.vmsnapshot.memory=Snapshot memory
+message.action.vmsnapshot.delete=Please confirm that you want to delete this VM snapshot.
+label.action.vmsnapshot.delete=Delete VM snapshot
+label.action.vmsnapshot.revert=Revert to VM snapshot
+message.action.vmsnapshot.revert=Revert VM snapshot
+label.action.vmsnapshot.create=Take VM Snapshot
+
+
+
#Messages
message.acquire.public.ip=Please select a zone from which you want to acquire your new IP from.
message.action.cancel.maintenance.mode=Please confirm that you want to cancel this maintenance.
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/9a12756a/client/tomcatconf/commands.properties.in
----------------------------------------------------------------------
diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in
index d70649b..e1d0fb2 100644
--- a/client/tomcatconf/commands.properties.in
+++ b/client/tomcatconf/commands.properties.in
@@ -537,3 +537,9 @@ addRegion=1
updateRegion=1
removeRegion=1
listRegions=15
+
+### VM Snapshot commands
+listVMSnapshot=15
+createVMSnapshot=15
+deleteVMSnapshot=15
+revertToSnapshot=15
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/9a12756a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManager.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManager.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManager.java
index f27e026..a2e517d 100644
--- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManager.java
+++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManager.java
@@ -20,15 +20,21 @@ import com.cloud.agent.api.Answer;
import com.cloud.agent.api.BackupSnapshotCommand;
import com.cloud.agent.api.CreatePrivateTemplateFromSnapshotCommand;
import com.cloud.agent.api.CreatePrivateTemplateFromVolumeCommand;
+import com.cloud.agent.api.CreateVMSnapshotCommand;
import com.cloud.agent.api.CreateVolumeFromSnapshotCommand;
+import com.cloud.agent.api.DeleteVMSnapshotCommand;
+import com.cloud.agent.api.RevertToVMSnapshotCommand;
import com.cloud.agent.api.storage.CopyVolumeCommand;
import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand;
public interface VmwareStorageManager {
Answer execute(VmwareHostService hostService, PrimaryStorageDownloadCommand cmd);
- Answer execute(VmwareHostService hostService, BackupSnapshotCommand cmd);
- Answer execute(VmwareHostService hostService, CreatePrivateTemplateFromVolumeCommand cmd);
- Answer execute(VmwareHostService hostService, CreatePrivateTemplateFromSnapshotCommand cmd);
- Answer execute(VmwareHostService hostService, CopyVolumeCommand cmd);
- Answer execute(VmwareHostService hostService, CreateVolumeFromSnapshotCommand cmd);
+ Answer execute(VmwareHostService hostService, BackupSnapshotCommand cmd);
+ Answer execute(VmwareHostService hostService, CreatePrivateTemplateFromVolumeCommand cmd);
+ Answer execute(VmwareHostService hostService, CreatePrivateTemplateFromSnapshotCommand cmd);
+ Answer execute(VmwareHostService hostService, CopyVolumeCommand cmd);
+ Answer execute(VmwareHostService hostService, CreateVolumeFromSnapshotCommand cmd);
+ Answer execute(VmwareHostService hostService, CreateVMSnapshotCommand cmd);
+ Answer execute(VmwareHostService hostService, DeleteVMSnapshotCommand cmd);
+ Answer execute(VmwareHostService hostService, RevertToVMSnapshotCommand cmd);
}
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/9a12756a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java
----------------------------------------------------------------------
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 8650274..c7b7cd3 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
@@ -22,6 +22,7 @@ import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.rmi.RemoteException;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.UUID;
@@ -32,18 +33,27 @@ import com.cloud.agent.api.BackupSnapshotAnswer;
import com.cloud.agent.api.BackupSnapshotCommand;
import com.cloud.agent.api.CreatePrivateTemplateFromSnapshotCommand;
import com.cloud.agent.api.CreatePrivateTemplateFromVolumeCommand;
+import com.cloud.agent.api.CreateVMSnapshotAnswer;
+import com.cloud.agent.api.CreateVMSnapshotCommand;
import com.cloud.agent.api.CreateVolumeFromSnapshotAnswer;
import com.cloud.agent.api.CreateVolumeFromSnapshotCommand;
+import com.cloud.agent.api.DeleteVMSnapshotAnswer;
+import com.cloud.agent.api.DeleteVMSnapshotCommand;
+import com.cloud.agent.api.RevertToVMSnapshotAnswer;
+import com.cloud.agent.api.RevertToVMSnapshotCommand;
import com.cloud.agent.api.storage.CopyVolumeAnswer;
import com.cloud.agent.api.storage.CopyVolumeCommand;
import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer;
import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer;
import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand;
import com.cloud.agent.api.to.StorageFilerTO;
+import com.cloud.agent.api.to.VolumeTO;
import com.cloud.hypervisor.vmware.mo.CustomFieldConstants;
import com.cloud.hypervisor.vmware.mo.DatacenterMO;
import com.cloud.hypervisor.vmware.mo.DatastoreMO;
+import com.cloud.hypervisor.vmware.mo.HostMO;
import com.cloud.hypervisor.vmware.mo.HypervisorHostHelper;
+import com.cloud.hypervisor.vmware.mo.TaskMO;
import com.cloud.hypervisor.vmware.mo.VirtualMachineMO;
import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost;
import com.cloud.hypervisor.vmware.util.VmwareContext;
@@ -57,7 +67,11 @@ 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;
+import com.cloud.vm.snapshot.VMSnapshot;
import com.vmware.vim25.ManagedObjectReference;
+import com.vmware.vim25.TaskEvent;
+import com.vmware.vim25.TaskInfo;
import com.vmware.vim25.VirtualDeviceConfigSpec;
import com.vmware.vim25.VirtualDeviceConfigSpecOperation;
import com.vmware.vim25.VirtualDisk;
@@ -222,8 +236,12 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager {
}
} finally {
- if(vmMo != null)
- vmMo.removeAllSnapshots();
+ if(vmMo != null){
+ ManagedObjectReference snapshotMor = vmMo.getSnapshotMor(snapshotUuid);
+ if (snapshotMor != null){
+ vmMo.removeSnapshot(snapshotUuid, false);
+ }
+ }
try {
if (workerVm != null) {
@@ -377,47 +395,47 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager {
}
@Override
- public Answer execute(VmwareHostService hostService, CreateVolumeFromSnapshotCommand cmd) {
+ public Answer execute(VmwareHostService hostService, CreateVolumeFromSnapshotCommand cmd) {
- String primaryStorageNameLabel = cmd.getPrimaryStoragePoolNameLabel();
- Long accountId = cmd.getAccountId();
- Long volumeId = cmd.getVolumeId();
- String secondaryStorageUrl = cmd.getSecondaryStorageUrl();
- String backedUpSnapshotUuid = cmd.getSnapshotUuid();
+ String primaryStorageNameLabel = cmd.getPrimaryStoragePoolNameLabel();
+ Long accountId = cmd.getAccountId();
+ Long volumeId = cmd.getVolumeId();
+ String secondaryStorageUrl = cmd.getSecondaryStorageUrl();
+ String backedUpSnapshotUuid = cmd.getSnapshotUuid();
- String details = null;
- boolean success = false;
- String newVolumeName = UUID.randomUUID().toString().replaceAll("-", "");
+ String details = null;
+ boolean success = false;
+ String newVolumeName = UUID.randomUUID().toString().replaceAll("-", "");
- VmwareContext context = hostService.getServiceContext(cmd);
- try {
- VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd);
-
- ManagedObjectReference morPrimaryDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, primaryStorageNameLabel);
- if (morPrimaryDs == null) {
- String msg = "Unable to find datastore: " + primaryStorageNameLabel;
- s_logger.error(msg);
- throw new Exception(msg);
- }
+ VmwareContext context = hostService.getServiceContext(cmd);
+ try {
+ VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd);
+ ManagedObjectReference morPrimaryDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost,
+ primaryStorageNameLabel);
+ if (morPrimaryDs == null) {
+ String msg = "Unable to find datastore: " + primaryStorageNameLabel;
+ s_logger.error(msg);
+ throw new Exception(msg);
+ }
- DatastoreMO primaryDsMo = new DatastoreMO(hyperHost.getContext(), morPrimaryDs);
- details = createVolumeFromSnapshot(hyperHost, primaryDsMo,
- newVolumeName, accountId, volumeId, secondaryStorageUrl, backedUpSnapshotUuid);
- if (details == null) {
- success = true;
- }
- } catch (Throwable e) {
- if (e instanceof RemoteException) {
- hostService.invalidateServiceContext(context);
- }
+ DatastoreMO primaryDsMo = new DatastoreMO(hyperHost.getContext(), morPrimaryDs);
+ details = createVolumeFromSnapshot(hyperHost, primaryDsMo,
+ newVolumeName, accountId, volumeId, secondaryStorageUrl, backedUpSnapshotUuid);
+ if (details == null) {
+ success = true;
+ }
+ } catch (Throwable e) {
+ if (e instanceof RemoteException) {
+ hostService.invalidateServiceContext(context);
+ }
+
+ s_logger.error("Unexpecpted exception ", e);
+ details = "CreateVolumeFromSnapshotCommand exception: " + StringUtils.getExceptionStackInfo(e);
+ }
- s_logger.error("Unexpecpted exception ", e);
- details = "CreateVolumeFromSnapshotCommand exception: " + StringUtils.getExceptionStackInfo(e);
- }
+ return new CreateVolumeFromSnapshotAnswer(cmd, success, details, newVolumeName);
+ }
- return new CreateVolumeFromSnapshotAnswer(cmd, success, details, newVolumeName);
- }
-
// templateName: name in secondary storage
// templateUuid: will be used at hypervisor layer
private void copyTemplateFromSecondaryToPrimary(VmwareHypervisorHost hyperHost, DatastoreMO datastoreMo, String secondaryStorageUrl,
@@ -881,4 +899,244 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager {
private static String getSnapshotRelativeDirInSecStorage(long accountId, long volumeId) {
return "snapshots/" + accountId + "/" + volumeId;
}
+
+ @Override
+ public CreateVMSnapshotAnswer execute(VmwareHostService hostService, CreateVMSnapshotCommand cmd) {
+ List<VolumeTO> volumeTOs = cmd.getVolumeTOs();
+ String vmName = cmd.getVmName();
+ String vmSnapshotName = cmd.getTarget().getSnapshotName();
+ String vmSnapshotDesc = cmd.getTarget().getDescription();
+ boolean snapshotMemory = cmd.getTarget().getType() == VMSnapshot.Type.DiskAndMemory;
+ VirtualMachineMO vmMo = null;
+ VmwareContext context = hostService.getServiceContext(cmd);
+ Map<String, String> mapNewDisk = new HashMap<String, String>();
+ try {
+ VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd);
+
+ // wait if there are already VM snapshot task running
+ ManagedObjectReference taskmgr = context.getServiceContent().getTaskManager();
+ ManagedObjectReference[] tasks = (ManagedObjectReference[]) context.getServiceUtil().getDynamicProperty(taskmgr, "recentTask");
+ for (ManagedObjectReference taskMor : tasks) {
+ TaskInfo info = (TaskInfo) (context.getServiceUtil().getDynamicProperty(taskMor, "info"));
+ if(info.getEntityName().equals(cmd.getVmName()) && info.getName().equalsIgnoreCase("CreateSnapshot_Task")){
+ s_logger.debug("There is already a VM snapshot task running, wait for it");
+ context.getServiceUtil().waitForTask(taskMor);
+ }
+ }
+
+ vmMo = hyperHost.findVmOnHyperHost(vmName);
+ if(vmMo == null)
+ vmMo = hyperHost.findVmOnPeerHyperHost(vmName);
+ if (vmMo == null) {
+ String msg = "Unable to find VM for CreateVMSnapshotCommand";
+ s_logger.debug(msg);
+ return new CreateVMSnapshotAnswer(cmd, false, msg);
+ } else {
+ if (vmMo.getSnapshotMor(vmSnapshotName) != null){
+ s_logger.debug("VM snapshot " + vmSnapshotName + " already exists");
+ }else if (!vmMo.createSnapshot(vmSnapshotName, vmSnapshotDesc, snapshotMemory, true)) {
+ return new CreateVMSnapshotAnswer(cmd, false,
+ "Unable to create snapshot due to esxi internal failed");
+ }
+ // find VM disk file path after creating snapshot
+ VirtualDisk[] vdisks = vmMo.getAllDiskDevice();
+ for (int i = 0; i < vdisks.length; i ++){
+ @SuppressWarnings("deprecation")
+ List<Pair<String, ManagedObjectReference>> vmdkFiles = vmMo.getDiskDatastorePathChain(vdisks[i], false);
+ for(Pair<String, ManagedObjectReference> fileItem : vmdkFiles) {
+ String vmdkName = fileItem.first().split(" ")[1];
+ if ( vmdkName.endsWith(".vmdk")){
+ vmdkName = vmdkName.substring(0, vmdkName.length() - (".vmdk").length());
+ }
+ String[] s = vmdkName.split("-");
+ mapNewDisk.put(s[0], vmdkName);
+ }
+ }
+
+ // update volume path using maps
+ for (VolumeTO volumeTO : volumeTOs) {
+ String parentUUID = volumeTO.getPath();
+ String[] s = parentUUID.split("-");
+ String key = s[0];
+ volumeTO.setPath(mapNewDisk.get(key));
+ }
+ return new CreateVMSnapshotAnswer(cmd, cmd.getTarget(), volumeTOs);
+ }
+ } catch (Exception e) {
+ String msg = e.getMessage();
+ s_logger.error("failed to create snapshot for vm:" + vmName + " due to " + msg);
+ try {
+ if (vmMo.getSnapshotMor(vmSnapshotName) != null) {
+ vmMo.removeSnapshot(vmSnapshotName, false);
+ }
+ } catch (Exception e1) {
+ }
+ return new CreateVMSnapshotAnswer(cmd, false, e.getMessage());
+ }
+ }
+
+ @Override
+ public DeleteVMSnapshotAnswer execute(VmwareHostService hostService, DeleteVMSnapshotCommand cmd) {
+ List<VolumeTO> listVolumeTo = cmd.getVolumeTOs();
+ VirtualMachineMO vmMo = null;
+ VmwareContext context = hostService.getServiceContext(cmd);
+ Map<String, String> mapNewDisk = new HashMap<String, String>();
+ String vmName = cmd.getVmName();
+ String vmSnapshotName = cmd.getTarget().getSnapshotName();
+ try {
+ VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd);
+ vmMo = hyperHost.findVmOnHyperHost(vmName);
+ if(vmMo == null)
+ vmMo = hyperHost.findVmOnPeerHyperHost(vmName);
+ if (vmMo == null) {
+ String msg = "Unable to find VM for RevertToVMSnapshotCommand";
+ s_logger.debug(msg);
+ return new DeleteVMSnapshotAnswer(cmd, false, msg);
+ } else {
+ if (vmMo.getSnapshotMor(vmSnapshotName) == null) {
+ s_logger.debug("can not find the snapshot " + vmSnapshotName + ", assume it is already removed");
+ } else {
+ if (!vmMo.removeSnapshot(vmSnapshotName, false)) {
+ String msg = "delete vm snapshot " + vmSnapshotName + " due to error occured in vmware";
+ s_logger.error(msg);
+ return new DeleteVMSnapshotAnswer(cmd, false, msg);
+ }
+ }
+ s_logger.debug("snapshot: " + vmSnapshotName + " is removed");
+ // after removed snapshot, the volumes' paths have been changed for the VM, needs to report new paths to manager
+ VirtualDisk[] vdisks = vmMo.getAllDiskDevice();
+ for (int i = 0; i < vdisks.length; i++) {
+ @SuppressWarnings("deprecation")
+ List<Pair<String, ManagedObjectReference>> vmdkFiles = vmMo.getDiskDatastorePathChain(vdisks[i], false);
+ for (Pair<String, ManagedObjectReference> fileItem : vmdkFiles) {
+ String vmdkName = fileItem.first().split(" ")[1];
+ if (vmdkName.endsWith(".vmdk")) {
+ vmdkName = vmdkName.substring(0, vmdkName.length() - (".vmdk").length());
+ }
+ String[] s = vmdkName.split("-");
+ mapNewDisk.put(s[0], vmdkName);
+ }
+ }
+ for (VolumeTO volumeTo : listVolumeTo) {
+ String key = null;
+ String parentUUID = volumeTo.getPath();
+ String[] s = parentUUID.split("-");
+ key = s[0];
+ volumeTo.setPath(mapNewDisk.get(key));
+ }
+ return new DeleteVMSnapshotAnswer(cmd, listVolumeTo);
+ }
+ } catch (Exception e) {
+ String msg = e.getMessage();
+ s_logger.error("failed to delete vm snapshot " + vmSnapshotName + " of vm " + vmName + " due to " + msg);
+ return new DeleteVMSnapshotAnswer(cmd, false, msg);
+ }
+ }
+
+ @Override
+ public RevertToVMSnapshotAnswer execute(VmwareHostService hostService, RevertToVMSnapshotCommand cmd) {
+ String snapshotName = cmd.getTarget().getSnapshotName();
+ String vmName = cmd.getVmName();
+ Boolean snapshotMemory = cmd.getTarget().getType() == VMSnapshot.Type.DiskAndMemory;
+ List<VolumeTO> listVolumeTo = cmd.getVolumeTOs();
+ VirtualMachine.State vmState = VirtualMachine.State.Running;
+ VirtualMachineMO vmMo = null;
+ VmwareContext context = hostService.getServiceContext(cmd);
+ Map<String, String> mapNewDisk = new HashMap<String, String>();
+ try {
+ VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd);
+
+ // wait if there are already VM revert task running
+ ManagedObjectReference taskmgr = context.getServiceContent().getTaskManager();
+ ManagedObjectReference[] tasks = (ManagedObjectReference[]) context.getServiceUtil().getDynamicProperty(taskmgr, "recentTask");
+ for (ManagedObjectReference taskMor : tasks) {
+ TaskInfo info = (TaskInfo) (context.getServiceUtil().getDynamicProperty(taskMor, "info"));
+ if(info.getEntityName().equals(cmd.getVmName()) && info.getName().equalsIgnoreCase("RevertToSnapshot_Task")){
+ s_logger.debug("There is already a VM snapshot task running, wait for it");
+ context.getServiceUtil().waitForTask(taskMor);
+ }
+ }
+
+ HostMO hostMo = (HostMO) hyperHost;
+ vmMo = hyperHost.findVmOnHyperHost(vmName);
+ if(vmMo == null)
+ vmMo = hyperHost.findVmOnPeerHyperHost(vmName);
+ if (vmMo == null) {
+ String msg = "Unable to find VM for RevertToVMSnapshotCommand";
+ s_logger.debug(msg);
+ return new RevertToVMSnapshotAnswer(cmd, false, msg);
+ } else {
+ boolean result = false;
+ if (snapshotName != null) {
+ ManagedObjectReference morSnapshot = vmMo.getSnapshotMor(snapshotName);
+ result = hostMo.revertToSnapshot(morSnapshot);
+ } else {
+ return new RevertToVMSnapshotAnswer(cmd, false, "Unable to find the snapshot by name " + snapshotName);
+ }
+
+ if (result) {
+ VirtualDisk[] vdisks = vmMo.getAllDiskDevice();
+ // build a map<volumeName, vmdk>
+ for (int i = 0; i < vdisks.length; i++) {
+ @SuppressWarnings("deprecation")
+ List<Pair<String, ManagedObjectReference>> vmdkFiles = vmMo.getDiskDatastorePathChain(
+ vdisks[i], false);
+ for (Pair<String, ManagedObjectReference> fileItem : vmdkFiles) {
+ String vmdkName = fileItem.first().split(" ")[1];
+ if (vmdkName.endsWith(".vmdk")) {
+ vmdkName = vmdkName.substring(0, vmdkName.length() - (".vmdk").length());
+ }
+ String[] s = vmdkName.split("-");
+ mapNewDisk.put(s[0], vmdkName);
+ }
+ }
+ String key = null;
+ for (VolumeTO volumeTo : listVolumeTo) {
+ String parentUUID = volumeTo.getPath();
+ String[] s = parentUUID.split("-");
+ key = s[0];
+ volumeTo.setPath(mapNewDisk.get(key));
+ }
+ if (!snapshotMemory) {
+ vmState = VirtualMachine.State.Stopped;
+ }
+ return new RevertToVMSnapshotAnswer(cmd, listVolumeTo, vmState);
+ } else {
+ return new RevertToVMSnapshotAnswer(cmd, false,
+ "Error while reverting to snapshot due to execute in esxi");
+ }
+ }
+ } catch (Exception e) {
+ String msg = "revert vm " + vmName + " to snapshot " + snapshotName + " failed due to " + e.getMessage();
+ s_logger.error(msg);
+ return new RevertToVMSnapshotAnswer(cmd, false, msg);
+ }
+ }
+
+
+ private VirtualMachineMO createWorkingVM(DatastoreMO dsMo, VmwareHypervisorHost hyperHost) throws Exception {
+ String uniqueName = UUID.randomUUID().toString();
+ VirtualMachineMO workingVM = null;
+ VirtualMachineConfigSpec vmConfig = new VirtualMachineConfigSpec();
+ vmConfig.setName(uniqueName);
+ vmConfig.setMemoryMB((long) 4);
+ vmConfig.setNumCPUs(1);
+ vmConfig.setGuestId(VirtualMachineGuestOsIdentifier._otherGuest.toString());
+ VirtualMachineFileInfo fileInfo = new VirtualMachineFileInfo();
+ fileInfo.setVmPathName(String.format("[%s]", dsMo.getName()));
+ vmConfig.setFiles(fileInfo);
+
+ VirtualLsiLogicController scsiController = new VirtualLsiLogicController();
+ scsiController.setSharedBus(VirtualSCSISharing.noSharing);
+ scsiController.setBusNumber(0);
+ scsiController.setKey(1);
+ VirtualDeviceConfigSpec scsiControllerSpec = new VirtualDeviceConfigSpec();
+ scsiControllerSpec.setDevice(scsiController);
+ scsiControllerSpec.setOperation(VirtualDeviceConfigSpecOperation.add);
+
+ vmConfig.setDeviceChange(new VirtualDeviceConfigSpec[] { scsiControllerSpec });
+ hyperHost.createVm(vmConfig);
+ workingVM = hyperHost.findVmOnHyperHost(uniqueName);
+ return workingVM;
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/9a12756a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
index 841a535..5cac253 100755
--- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
+++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
@@ -65,9 +65,13 @@ import com.cloud.agent.api.Command;
import com.cloud.agent.api.CreatePrivateTemplateFromSnapshotCommand;
import com.cloud.agent.api.CreatePrivateTemplateFromVolumeCommand;
import com.cloud.agent.api.CreateStoragePoolCommand;
+import com.cloud.agent.api.CreateVMSnapshotAnswer;
+import com.cloud.agent.api.CreateVMSnapshotCommand;
import com.cloud.agent.api.CreateVolumeFromSnapshotAnswer;
import com.cloud.agent.api.CreateVolumeFromSnapshotCommand;
import com.cloud.agent.api.DeleteStoragePoolCommand;
+import com.cloud.agent.api.DeleteVMSnapshotAnswer;
+import com.cloud.agent.api.DeleteVMSnapshotCommand;
import com.cloud.agent.api.GetDomRVersionAnswer;
import com.cloud.agent.api.GetDomRVersionCmd;
import com.cloud.agent.api.GetHostStatsAnswer;
@@ -103,6 +107,8 @@ import com.cloud.agent.api.ReadyCommand;
import com.cloud.agent.api.RebootAnswer;
import com.cloud.agent.api.RebootCommand;
import com.cloud.agent.api.RebootRouterCommand;
+import com.cloud.agent.api.RevertToVMSnapshotAnswer;
+import com.cloud.agent.api.RevertToVMSnapshotCommand;
import com.cloud.agent.api.SetupAnswer;
import com.cloud.agent.api.SetupCommand;
import com.cloud.agent.api.SetupGuestNetworkAnswer;
@@ -445,7 +451,13 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
answer = execute((SetSourceNatCommand) cmd);
} else if (clz == SetNetworkACLCommand.class) {
answer = execute((SetNetworkACLCommand) cmd);
- } else if (clz == SetPortForwardingRulesVpcCommand.class) {
+ } else if (cmd instanceof CreateVMSnapshotCommand) {
+ return execute((CreateVMSnapshotCommand)cmd);
+ } else if(cmd instanceof DeleteVMSnapshotCommand){
+ return execute((DeleteVMSnapshotCommand)cmd);
+ } else if(cmd instanceof RevertToVMSnapshotCommand){
+ return execute((RevertToVMSnapshotCommand)cmd);
+ }else if (clz == SetPortForwardingRulesVpcCommand.class) {
answer = execute((SetPortForwardingRulesVpcCommand) cmd);
} else if (clz == Site2SiteVpnCfgCommand.class) {
answer = execute((Site2SiteVpnCfgCommand) cmd);
@@ -2799,7 +2811,6 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
// before we stop VM, remove all possible snapshots on the VM to let
// disk chain be collapsed
s_logger.info("Remove all snapshot before stopping VM " + cmd.getVmName());
- vmMo.removeAllSnapshots();
if (vmMo.safePowerOff(_shutdown_waitMs)) {
state = State.Stopped;
return new StopAnswer(cmd, "Stop VM " + cmd.getVmName() + " Succeed", 0, true);
@@ -3351,7 +3362,42 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
}
}
+ protected Answer execute(CreateVMSnapshotCommand cmd) {
+ try {
+ VmwareContext context = getServiceContext();
+ VmwareManager mgr = context
+ .getStockObject(VmwareManager.CONTEXT_STOCK_NAME);
+
+ return mgr.getStorageManager().execute(this, cmd);
+ } catch (Exception e) {
+ e.printStackTrace();
+ return new CreateVMSnapshotAnswer(cmd, false, "");
+ }
+ }
+
+ protected Answer execute(DeleteVMSnapshotCommand cmd) {
+ try {
+ VmwareContext context = getServiceContext();
+ VmwareManager mgr = context
+ .getStockObject(VmwareManager.CONTEXT_STOCK_NAME);
+ return mgr.getStorageManager().execute(this, cmd);
+ } catch (Exception e) {
+ e.printStackTrace();
+ return new DeleteVMSnapshotAnswer(cmd, false, "");
+ }
+ }
+
+ protected Answer execute(RevertToVMSnapshotCommand cmd){
+ try{
+ VmwareContext context = getServiceContext();
+ VmwareManager mgr = context.getStockObject(VmwareManager.CONTEXT_STOCK_NAME);
+ return mgr.getStorageManager().execute(this, cmd);
+ }catch (Exception e){
+ e.printStackTrace();
+ return new RevertToVMSnapshotAnswer(cmd,false,"");
+ }
+ }
protected Answer execute(CreateVolumeFromSnapshotCommand cmd) {
if (s_logger.isInfoEnabled()) {
s_logger.info("Executing resource CreateVolumeFromSnapshotCommand: " + _gson.toJson(cmd));
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/9a12756a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
index b3cb54f..22f4ba9 100644
--- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
+++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
@@ -90,9 +90,13 @@ import com.cloud.agent.api.Command;
import com.cloud.agent.api.CreatePrivateTemplateFromSnapshotCommand;
import com.cloud.agent.api.CreatePrivateTemplateFromVolumeCommand;
import com.cloud.agent.api.CreateStoragePoolCommand;
+import com.cloud.agent.api.CreateVMSnapshotAnswer;
+import com.cloud.agent.api.CreateVMSnapshotCommand;
import com.cloud.agent.api.CreateVolumeFromSnapshotAnswer;
import com.cloud.agent.api.CreateVolumeFromSnapshotCommand;
import com.cloud.agent.api.DeleteStoragePoolCommand;
+import com.cloud.agent.api.DeleteVMSnapshotAnswer;
+import com.cloud.agent.api.DeleteVMSnapshotCommand;
import com.cloud.agent.api.GetDomRVersionAnswer;
import com.cloud.agent.api.GetDomRVersionCmd;
import com.cloud.agent.api.GetHostStatsAnswer;
@@ -129,6 +133,8 @@ import com.cloud.agent.api.ReadyCommand;
import com.cloud.agent.api.RebootAnswer;
import com.cloud.agent.api.RebootCommand;
import com.cloud.agent.api.RebootRouterCommand;
+import com.cloud.agent.api.RevertToVMSnapshotAnswer;
+import com.cloud.agent.api.RevertToVMSnapshotCommand;
import com.cloud.agent.api.SecurityGroupRuleAnswer;
import com.cloud.agent.api.SecurityGroupRulesCmd;
import com.cloud.agent.api.SetupAnswer;
@@ -237,6 +243,7 @@ import com.cloud.utils.net.NetUtils;
import com.cloud.vm.DiskProfile;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachine.State;
+import com.cloud.vm.snapshot.VMSnapshot;
import com.trilead.ssh2.SCPClient;
import com.xensource.xenapi.Bond;
import com.xensource.xenapi.Connection;
@@ -256,6 +263,10 @@ import com.xensource.xenapi.Types;
import com.xensource.xenapi.Types.BadServerResponse;
import com.xensource.xenapi.Types.ConsoleProtocol;
import com.xensource.xenapi.Types.IpConfigurationMode;
+import com.xensource.xenapi.Types.OperationNotAllowed;
+import com.xensource.xenapi.Types.SrFull;
+import com.xensource.xenapi.Types.VbdType;
+import com.xensource.xenapi.Types.VmBadPowerState;
import com.xensource.xenapi.Types.VmPowerState;
import com.xensource.xenapi.Types.XenAPIException;
import com.xensource.xenapi.VBD;
@@ -579,11 +590,109 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
return execute((CheckS2SVpnConnectionsCommand) cmd);
} else if (cmd instanceof StorageSubSystemCommand) {
return this.storageResource.handleStorageCommands((StorageSubSystemCommand)cmd);
+ } else if (clazz == CreateVMSnapshotCommand.class) {
+ return execute((CreateVMSnapshotCommand)cmd);
+ } else if (clazz == DeleteVMSnapshotCommand.class) {
+ return execute((DeleteVMSnapshotCommand)cmd);
+ } else if (clazz == RevertToVMSnapshotCommand.class) {
+ return execute((RevertToVMSnapshotCommand)cmd);
} else {
return Answer.createUnsupportedCommandAnswer(cmd);
}
}
+
+
+ private Answer execute(RevertToVMSnapshotCommand cmd) {
+ String vmName = cmd.getVmName();
+ List<VolumeTO> listVolumeTo = cmd.getVolumeTOs();
+ VMSnapshot.Type vmSnapshotType = cmd.getTarget().getType();
+ Boolean snapshotMemory = vmSnapshotType == VMSnapshot.Type.DiskAndMemory;
+ Connection conn = getConnection();
+ VirtualMachine.State vmState = null;
+ VM vm = null;
+ try {
+
+ // remove vm from s_vms, for delta sync
+ s_vms.remove(_cluster, _name, vmName);
+
+ Set<VM> vmSnapshots = VM.getByNameLabel(conn, cmd.getTarget().getSnapshotName());
+ if(vmSnapshots.size() == 0)
+ return new RevertToVMSnapshotAnswer(cmd, false, "Cannot find vmSnapshot with name: " + cmd.getTarget().getSnapshotName());
+
+ VM vmSnapshot = vmSnapshots.iterator().next();
+
+ // find target VM or creating a work VM
+ try {
+ vm = getVM(conn, vmName);
+ } catch (Exception e) {
+ vm = createWorkingVM(conn, vmName, cmd.getGuestOSType(), listVolumeTo);
+ }
+
+ if (vm == null) {
+ return new RevertToVMSnapshotAnswer(cmd, false,
+ "Revert to VM Snapshot Failed due to can not find vm: " + vmName);
+ }
+
+ // call plugin to execute revert
+ revertToSnapshot(conn, vmSnapshot, vmName, vm.getUuid(conn), snapshotMemory, _host.uuid);
+ vm = getVM(conn, vmName);
+ Set<VBD> vbds = vm.getVBDs(conn);
+ Map<String, VDI> vdiMap = new HashMap<String, VDI>();
+ // get vdi:vbdr to a map
+ for (VBD vbd : vbds) {
+ VBD.Record vbdr = vbd.getRecord(conn);
+ if (vbdr.type == Types.VbdType.DISK) {
+ VDI vdi = vbdr.VDI;
+ vdiMap.put(vbdr.userdevice, vdi);
+ }
+ }
+
+ if (!snapshotMemory) {
+ vm.destroy(conn);
+ vmState = VirtualMachine.State.Stopped;
+ } else {
+ s_vms.put(_cluster, _name, vmName, State.Running);
+ vmState = VirtualMachine.State.Running;
+ }
+
+ // after revert, VM's volumes path have been changed, need to report to manager
+ for (VolumeTO volumeTo : listVolumeTo) {
+ Long deviceId = volumeTo.getDeviceId();
+ VDI vdi = vdiMap.get(deviceId.toString());
+ volumeTo.setPath(vdi.getUuid(conn));
+ }
+
+ return new RevertToVMSnapshotAnswer(cmd, listVolumeTo,vmState);
+ } catch (Exception e) {
+ s_logger.error("revert vm " + vmName
+ + " to snapshot " + cmd.getTarget().getSnapshotName() + " failed due to " + e.getMessage());
+ return new RevertToVMSnapshotAnswer(cmd, false, e.getMessage());
+ }
+ }
+
+ private String revertToSnapshot(Connection conn, VM vmSnapshot,
+ String vmName, String oldVmUuid, Boolean snapshotMemory, String hostUUID)
+ throws XenAPIException, XmlRpcException {
+
+ String results = callHostPluginAsync(conn, "vmopsSnapshot",
+ "revert_memory_snapshot", 10 * 60 * 1000, "snapshotUUID",
+ vmSnapshot.getUuid(conn), "vmName", vmName, "oldVmUuid",
+ oldVmUuid, "snapshotMemory", snapshotMemory.toString(), "hostUUID", hostUUID);
+ String errMsg = null;
+ if (results == null || results.isEmpty()) {
+ errMsg = "revert_memory_snapshot return null";
+ } else {
+ if (results.equals("0")) {
+ return results;
+ } else {
+ errMsg = "revert_memory_snapshot exception";
+ }
+ }
+ s_logger.warn(errMsg);
+ throw new CloudRuntimeException(errMsg);
+ }
+
protected XsLocalNetwork getNativeNetworkForTraffic(Connection conn, TrafficType type, String name) throws XenAPIException, XmlRpcException {
if (name != null) {
if (s_logger.isDebugEnabled()) {
@@ -6167,6 +6276,199 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
}
+ protected Answer execute(final CreateVMSnapshotCommand cmd) {
+ String vmName = cmd.getVmName();
+ String vmSnapshotName = cmd.getTarget().getSnapshotName();
+ List<VolumeTO> listVolumeTo = cmd.getVolumeTOs();
+ VirtualMachine.State vmState = cmd.getVmState();
+ String guestOSType = cmd.getGuestOSType();
+
+ boolean snapshotMemory = cmd.getTarget().getType() == VMSnapshot.Type.DiskAndMemory;
+ long timeout = 600;
+
+ Connection conn = getConnection();
+ VM vm = null;
+ VM vmSnapshot = null;
+ boolean success = false;
+
+ try {
+ // check if VM snapshot already exists
+ Set<VM> vmSnapshots = VM.getByNameLabel(conn, cmd.getTarget().getSnapshotName());
+ if(vmSnapshots.size() > 0)
+ return new CreateVMSnapshotAnswer(cmd, cmd.getTarget(), cmd.getVolumeTOs());
+
+ // check if there is already a task for this VM snapshot
+ Task task = null;
+ Set<Task> tasks = Task.getByNameLabel(conn, "Async.VM.snapshot");
+ tasks.addAll(Task.getByNameLabel(conn, "Async.VM.checkpoint"));
+ for (Task taskItem : tasks) {
+ if(taskItem.getOtherConfig(conn).containsKey("CS_VM_SNAPSHOT_KEY")){
+ String vmSnapshotTaskName = taskItem.getOtherConfig(conn).get("CS_VM_SNAPSHOT_KEY");
+ if(vmSnapshotTaskName != null && vmSnapshotTaskName.equals(cmd.getTarget().getSnapshotName())){
+ task = taskItem;
+ }
+ }
+ }
+
+ // create a new task if there is no existing task for this VM snapshot
+ if(task == null){
+ try {
+ vm = getVM(conn, vmName);
+ } catch (Exception e) {
+ if (!snapshotMemory) {
+ vm = createWorkingVM(conn, vmName, guestOSType, listVolumeTo);
+ }
+ }
+
+ if (vm == null) {
+ return new CreateVMSnapshotAnswer(cmd, false,
+ "Creating VM Snapshot Failed due to can not find vm: "
+ + vmName);
+ }
+
+ // call Xenserver API
+ if (!snapshotMemory) {
+ task = vm.snapshotAsync(conn, vmSnapshotName);
+ } else {
+ Set<VBD> vbds = vm.getVBDs(conn);
+ Pool pool = Pool.getByUuid(conn, _host.pool);
+ for (VBD vbd: vbds){
+ VBD.Record vbdr = vbd.getRecord(conn);
+ if (vbdr.userdevice.equals("0")){
+ VDI vdi = vbdr.VDI;
+ SR sr = vdi.getSR(conn);
+ // store memory image on the same SR with ROOT volume
+ pool.setSuspendImageSR(conn, sr);
+ }
+ }
+ task = vm.checkpointAsync(conn, vmSnapshotName);
+ }
+ task.addToOtherConfig(conn, "CS_VM_SNAPSHOT_KEY", vmSnapshotName);
+ }
+
+ waitForTask(conn, task, 1000, timeout * 1000);
+ checkForSuccess(conn, task);
+ String result = task.getResult(conn);
+
+ // extract VM snapshot ref from result
+ String ref = result.substring("<value>".length(), result.length() - "</value>".length());
+ vmSnapshot = Types.toVM(ref);
+
+ success = true;
+ return new CreateVMSnapshotAnswer(cmd, cmd.getTarget(), cmd.getVolumeTOs());
+ } catch (Exception e) {
+ String msg = e.getMessage();
+ s_logger.error("Creating VM Snapshot " + cmd.getTarget().getSnapshotName() + " failed due to: " + msg);
+ return new CreateVMSnapshotAnswer(cmd, false, msg);
+ } finally {
+ try {
+ if (!success) {
+ if (vmSnapshot != null) {
+ s_logger.debug("Delete exsisting VM Snapshot "
+ + vmSnapshotName
+ + " after making VolumeTO failed");
+ Set<VBD> vbds = vmSnapshot.getVBDs(conn);
+ for (VBD vbd : vbds) {
+ VBD.Record vbdr = vbd.getRecord(conn);
+ if (vbdr.type == VbdType.DISK) {
+ VDI vdi = vbdr.VDI;
+ vdi.destroy(conn);
+ }
+ }
+ vmSnapshot.destroy(conn);
+ }
+ }
+ if (vmState == VirtualMachine.State.Stopped) {
+ if (vm != null) {
+ vm.destroy(conn);
+ }
+ }
+ } catch (Exception e2) {
+ s_logger.error("delete snapshot error due to "
+ + e2.getMessage());
+ }
+ }
+ }
+
+ private VM createWorkingVM(Connection conn, String vmName,
+ String guestOSType, List<VolumeTO> listVolumeTo)
+ throws BadServerResponse, VmBadPowerState, SrFull,
+ OperationNotAllowed, XenAPIException, XmlRpcException {
+ String guestOsTypeName = getGuestOsType(guestOSType, false);
+ if (guestOsTypeName == null) {
+ String msg = " Hypervisor " + this.getClass().getName()
+ + " doesn't support guest OS type " + guestOSType
+ + ". you can choose 'Other install media' to run it as HVM";
+ s_logger.warn(msg);
+ throw new CloudRuntimeException(msg);
+ }
+ VM template = getVM(conn, guestOsTypeName);
+ VM vm = template.createClone(conn, vmName);
+ vm.setIsATemplate(conn, false);
+ Map<VDI, VolumeTO> vdiMap = new HashMap<VDI, VolumeTO>();
+ for (VolumeTO volume : listVolumeTo) {
+ String vdiUuid = volume.getPath();
+ try {
+ VDI vdi = VDI.getByUuid(conn, vdiUuid);
+ vdiMap.put(vdi, volume);
+ } catch (Types.UuidInvalid e) {
+ s_logger.warn("Unable to find vdi by uuid: " + vdiUuid
+ + ", skip it");
+ }
+ }
+ for (VDI vdi : vdiMap.keySet()) {
+ VolumeTO volumeTO = vdiMap.get(vdi);
+ VBD.Record vbdr = new VBD.Record();
+ vbdr.VM = vm;
+ vbdr.VDI = vdi;
+ if (volumeTO.getType() == Volume.Type.ROOT) {
+ vbdr.bootable = true;
+ vbdr.unpluggable = false;
+ } else {
+ vbdr.bootable = false;
+ vbdr.unpluggable = true;
+ }
+ vbdr.userdevice = new Long(volumeTO.getDeviceId()).toString();
+ vbdr.mode = Types.VbdMode.RW;
+ vbdr.type = Types.VbdType.DISK;
+ VBD.create(conn, vbdr);
+ }
+ return vm;
+ }
+
+ protected Answer execute(final DeleteVMSnapshotCommand cmd) {
+ String snapshotName = cmd.getTarget().getSnapshotName();
+ Connection conn = getConnection();
+
+ try {
+ List<VDI> vdiList = new ArrayList<VDI>();
+ Set<VM> snapshots = VM.getByNameLabel(conn, snapshotName);
+ if(snapshots.size() == 0){
+ s_logger.warn("VM snapshot with name " + snapshotName + " does not exist, assume it is already deleted");
+ return new DeleteVMSnapshotAnswer(cmd, cmd.getVolumeTOs());
+ }
+ VM snapshot = snapshots.iterator().next();
+ Set<VBD> vbds = snapshot.getVBDs(conn);
+ for (VBD vbd : vbds) {
+ if (vbd.getType(conn) == VbdType.DISK) {
+ VDI vdi = vbd.getVDI(conn);
+ vdiList.add(vdi);
+ }
+ }
+ if(cmd.getTarget().getType() == VMSnapshot.Type.DiskAndMemory)
+ vdiList.add(snapshot.getSuspendVDI(conn));
+ snapshot.destroy(conn);
+ for (VDI vdi : vdiList) {
+ vdi.destroy(conn);
+ }
+ return new DeleteVMSnapshotAnswer(cmd, cmd.getVolumeTOs());
+ } catch (Exception e) {
+ s_logger.warn("Catch Exception: " + e.getClass().toString()
+ + " due to " + e.toString(), e);
+ return new DeleteVMSnapshotAnswer(cmd, false, e.getMessage());
+ }
+ }
+
protected Answer execute(final AttachIsoCommand cmd) {
Connection conn = getConnection();
boolean attach = cmd.isAttach();
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/9a12756a/scripts/vm/hypervisor/xenserver/vmopsSnapshot
----------------------------------------------------------------------
diff --git a/scripts/vm/hypervisor/xenserver/vmopsSnapshot b/scripts/vm/hypervisor/xenserver/vmopsSnapshot
index 39fe31c..6fb1b18 100755
--- a/scripts/vm/hypervisor/xenserver/vmopsSnapshot
+++ b/scripts/vm/hypervisor/xenserver/vmopsSnapshot
@@ -556,6 +556,33 @@ def deleteSnapshotBackup(session, args):
return "1"
+@echo
+def revert_memory_snapshot(session, args):
+ util.SMlog("Calling revert_memory_snapshot with " + str(args))
+ vmName = args['vmName']
+ snapshotUUID = args['snapshotUUID']
+ oldVmUuid = args['oldVmUuid']
+ snapshotMemory = args['snapshotMemory']
+ hostUUID = args['hostUUID']
+ try:
+ cmd = '''xe vbd-list vm-uuid=%s | grep 'vdi-uuid' | grep -v 'not in database' | sed -e 's/vdi-uuid ( RO)://g' ''' % oldVmUuid
+ vdiUuids = os.popen(cmd).read().split()
+ cmd2 = '''xe vm-param-get param-name=power-state uuid=''' + oldVmUuid
+ if os.popen(cmd2).read().split()[0] != 'halted':
+ os.system("xe vm-shutdown force=true vm=" + vmName)
+ os.system("xe vm-destroy uuid=" + oldVmUuid)
+ os.system("xe snapshot-revert snapshot-uuid=" + snapshotUUID)
+ if snapshotMemory == 'true':
+ os.system("xe vm-resume vm=" + vmName + " on=" + hostUUID)
+ for vdiUuid in vdiUuids:
+ os.system("xe vdi-destroy uuid=" + vdiUuid)
+ except OSError, (errno, strerror):
+ errMsg = "OSError while reverting vm " + vmName + " to snapshot " + snapshotUUID + " with errno: " + str(errno) + " and strerr: " + strerror
+ util.SMlog(errMsg)
+ raise xs_errors.XenError(errMsg)
+ return "0"
+
if __name__ == "__main__":
- XenAPIPlugin.dispatch({"getVhdParent":getVhdParent, "create_secondary_storage_folder":create_secondary_storage_folder, "delete_secondary_storage_folder":delete_secondary_storage_folder, "post_create_private_template":post_create_private_template, "backupSnapshot": backupSnapshot, "deleteSnapshotBackup": deleteSnapshotBackup, "unmountSnapshotsDir": unmountSnapshotsDir})
+ XenAPIPlugin.dispatch({"getVhdParent":getVhdParent, "create_secondary_storage_folder":create_secondary_storage_folder, "delete_secondary_storage_folder":delete_secondary_storage_folder, "post_create_private_template":post_create_private_template, "backupSnapshot": backupSnapshot, "deleteSnapshotBackup": deleteSnapshotBackup, "unmountSnapshotsDir": unmountSnapshotsDir, "revert_memory_snapshot":revert_memory_snapshot})
+
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/9a12756a/server/src/com/cloud/api/ApiDBUtils.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/ApiDBUtils.java b/server/src/com/cloud/api/ApiDBUtils.java
index 83132c6..e6b1bf1 100755
--- a/server/src/com/cloud/api/ApiDBUtils.java
+++ b/server/src/com/cloud/api/ApiDBUtils.java
@@ -209,6 +209,8 @@ import com.cloud.vm.dao.DomainRouterDao;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.UserVmDetailsDao;
import com.cloud.vm.dao.VMInstanceDao;
+import com.cloud.vm.snapshot.VMSnapshot;
+import com.cloud.vm.snapshot.dao.VMSnapshotDao;
@Component
public class ApiDBUtils {
@@ -309,6 +311,7 @@ public class ApiDBUtils {
static SnapshotPolicyDao _snapshotPolicyDao;
static AsyncJobDao _asyncJobDao;
static HostDetailsDao _hostDetailsDao;
+ static VMSnapshotDao _vmSnapshotDao;
@Inject private ManagementServer ms;
@Inject public AsyncJobManager asyncMgr;
@@ -407,7 +410,7 @@ public class ApiDBUtils {
@Inject private SnapshotPolicyDao snapshotPolicyDao;
@Inject private AsyncJobDao asyncJobDao;
@Inject private HostDetailsDao hostDetailsDao;
-
+ @Inject private VMSnapshotDao vmSnapshotDao;
@PostConstruct
void init() {
_ms = ms;
@@ -505,7 +508,7 @@ public class ApiDBUtils {
_snapshotPolicyDao = snapshotPolicyDao;
_asyncJobDao = asyncJobDao;
_hostDetailsDao = hostDetailsDao;
-
+ _vmSnapshotDao = vmSnapshotDao;
// Note: stats collector should already have been initialized by this time, otherwise a null instance is returned
_statsCollector = StatsCollector.getInstance();
}
@@ -1054,6 +1057,11 @@ public class ApiDBUtils {
return _networkModel.canUseForDeploy(network);
}
+ public static VMSnapshot getVMSnapshotById(Long vmSnapshotId) {
+ VMSnapshot vmSnapshot = _vmSnapshotDao.findById(vmSnapshotId);
+ return vmSnapshot;
+ }
+
public static String getUuid(String resourceId, TaggedResourceType resourceType) {
return _taggedResourceService.getUuid(resourceId, resourceType);
}
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/9a12756a/server/src/com/cloud/api/ApiResponseHelper.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java
index 8c97615..a94e935 100755
--- a/server/src/com/cloud/api/ApiResponseHelper.java
+++ b/server/src/com/cloud/api/ApiResponseHelper.java
@@ -93,7 +93,6 @@ import org.apache.cloudstack.api.response.VpcOfferingResponse;
import org.apache.cloudstack.api.response.VpcResponse;
import org.apache.cloudstack.api.response.VpnUsersResponse;
import org.apache.cloudstack.api.response.ZoneResponse;
-
import org.apache.cloudstack.api.response.S3Response;
import org.springframework.stereotype.Component;
@@ -195,6 +194,13 @@ import org.apache.cloudstack.region.Region;
import org.apache.cloudstack.usage.Usage;
import org.apache.cloudstack.usage.UsageService;
import org.apache.cloudstack.usage.UsageTypes;
+import com.cloud.vm.VmStats;
+import com.cloud.vm.dao.UserVmData;
+import com.cloud.vm.dao.UserVmData.NicData;
+import com.cloud.vm.dao.UserVmData.SecurityGroupData;
+import com.cloud.vm.snapshot.VMSnapshot;
+import org.apache.cloudstack.api.ResponseGenerator;
+import org.apache.cloudstack.api.response.VMSnapshotResponse;
import org.apache.log4j.Logger;
import java.text.DecimalFormat;
@@ -359,6 +365,25 @@ public class ApiResponseHelper implements ResponseGenerator {
}
@Override
+ public VMSnapshotResponse createVMSnapshotResponse(VMSnapshot vmSnapshot) {
+ VMSnapshotResponse vmSnapshotResponse = new VMSnapshotResponse();
+ vmSnapshotResponse.setId(vmSnapshot.getUuid());
+ vmSnapshotResponse.setName(vmSnapshot.getName());
+ vmSnapshotResponse.setState(vmSnapshot.getState());
+ vmSnapshotResponse.setCreated(vmSnapshot.getCreated());
+ vmSnapshotResponse.setDescription(vmSnapshot.getDescription());
+ vmSnapshotResponse.setDisplayName(vmSnapshot.getDisplayName());
+ UserVm vm = ApiDBUtils.findUserVmById(vmSnapshot.getVmId());
+ if(vm!=null)
+ vmSnapshotResponse.setVirtualMachineid(vm.getUuid());
+ if(vmSnapshot.getParent() != null)
+ vmSnapshotResponse.setParentName(ApiDBUtils.getVMSnapshotById(vmSnapshot.getParent()).getDisplayName());
+ vmSnapshotResponse.setCurrent(vmSnapshot.getCurrent());
+ vmSnapshotResponse.setType(vmSnapshot.getType().toString());
+ return vmSnapshotResponse;
+ }
+
+ @Override
public SnapshotPolicyResponse createSnapshotPolicyResponse(SnapshotPolicy policy) {
SnapshotPolicyResponse policyResponse = new SnapshotPolicyResponse();
policyResponse.setId(policy.getUuid());
@@ -3093,7 +3118,6 @@ public class ApiResponseHelper implements ResponseGenerator {
response.setObjectName("vpnconnection");
return response;
}
-
@Override
public GuestOSResponse createGuestOSResponse(GuestOS guestOS) {
GuestOSResponse response = new GuestOSResponse();
@@ -3133,7 +3157,6 @@ public class ApiResponseHelper implements ResponseGenerator {
}
-
@Override
public UsageRecordResponse createUsageResponse(Usage usageRecord) {
UsageRecordResponse usageRecResponse = new UsageRecordResponse();
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/9a12756a/server/src/com/cloud/capacity/CapacityManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/capacity/CapacityManagerImpl.java b/server/src/com/cloud/capacity/CapacityManagerImpl.java
index d7b7053..4787c7b 100755
--- a/server/src/com/cloud/capacity/CapacityManagerImpl.java
+++ b/server/src/com/cloud/capacity/CapacityManagerImpl.java
@@ -62,9 +62,11 @@ import com.cloud.storage.VMTemplateHostVO;
import com.cloud.storage.VMTemplateStoragePoolVO;
import com.cloud.storage.VMTemplateSwiftVO;
import com.cloud.storage.VMTemplateVO;
+import com.cloud.storage.VolumeVO;
import com.cloud.storage.dao.VMTemplatePoolDao;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.storage.swift.SwiftManager;
+import com.cloud.uservm.UserVm;
import com.cloud.utils.DateUtil;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.Pair;
@@ -78,7 +80,11 @@ import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachine.Event;
import com.cloud.vm.VirtualMachine.State;
+import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.VMInstanceDao;
+import com.cloud.vm.snapshot.VMSnapshot;
+import com.cloud.vm.snapshot.VMSnapshotVO;
+import com.cloud.vm.snapshot.dao.VMSnapshotDao;
@Component
@Local(value = CapacityManager.class)
@@ -110,7 +116,11 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager,
ConfigurationManager _configMgr;
@Inject
HypervisorCapabilitiesDao _hypervisorCapabilitiesDao;
-
+ @Inject
+ protected VMSnapshotDao _vmSnapshotDao;
+ @Inject
+ protected UserVmDao _userVMDao;
+
private int _vmCapacityReleaseInterval;
private ScheduledExecutorService _executor;
private boolean _stopped;
@@ -437,12 +447,43 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager,
}
+ private long getVMSnapshotAllocatedCapacity(StoragePoolVO pool){
+ List<VolumeVO> volumes = _volumeDao.findByPoolId(pool.getId());
+ long totalSize = 0;
+ for (VolumeVO volume : volumes) {
+ if(volume.getInstanceId() == null)
+ continue;
+ Long vmId = volume.getInstanceId();
+ UserVm vm = _userVMDao.findById(vmId);
+ if(vm == null)
+ continue;
+ ServiceOffering offering = _offeringsDao.findById(vm.getServiceOfferingId());
+ List<VMSnapshotVO> vmSnapshots = _vmSnapshotDao.findByVm(vmId);
+ long pathCount = 0;
+ long memorySnapshotSize = 0;
+ for (VMSnapshotVO vmSnapshotVO : vmSnapshots) {
+ if(_vmSnapshotDao.listByParent(vmSnapshotVO.getId()).size() == 0)
+ pathCount++;
+ if(vmSnapshotVO.getType() == VMSnapshot.Type.DiskAndMemory)
+ memorySnapshotSize += (offering.getRamSize() * 1024 * 1024);
+ }
+ if(pathCount <= 1)
+ totalSize = totalSize + memorySnapshotSize;
+ else
+ totalSize = totalSize + volume.getSize() * (pathCount - 1) + memorySnapshotSize;
+ }
+ return totalSize;
+ }
+
@Override
public long getAllocatedPoolCapacity(StoragePoolVO pool, VMTemplateVO templateForVmCreation){
// Get size for all the volumes
Pair<Long, Long> sizes = _volumeDao.getCountAndTotalByPool(pool.getId());
long totalAllocatedSize = sizes.second() + sizes.first() * _extraBytesPerVolume;
+
+ // Get size for VM Snapshots
+ totalAllocatedSize = totalAllocatedSize + getVMSnapshotAllocatedCapacity(pool);
// Iterate through all templates on this storage pool
boolean tmpinstalled = false;
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/9a12756a/server/src/com/cloud/configuration/Config.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/configuration/Config.java b/server/src/com/cloud/configuration/Config.java
index b1a1308..26499bc 100755
--- a/server/src/com/cloud/configuration/Config.java
+++ b/server/src/com/cloud/configuration/Config.java
@@ -33,6 +33,7 @@ import com.cloud.storage.secondary.SecondaryStorageVmManager;
import com.cloud.storage.snapshot.SnapshotManager;
import com.cloud.template.TemplateManager;
import com.cloud.vm.UserVmManager;
+import com.cloud.vm.snapshot.VMSnapshotManager;
public enum Config {
@@ -371,8 +372,16 @@ public enum Config {
ApiLimitInterval("Advanced", ManagementServer.class, Integer.class, "api.throttling.interval", "1", "Time interval (in seconds) to reset API count", null),
ApiLimitMax("Advanced", ManagementServer.class, Integer.class, "api.throttling.max", "25", "Max allowed number of APIs within fixed interval", null),
- ApiLimitCacheSize("Advanced", ManagementServer.class, Integer.class, "api.throttling.cachesize", "50000", "Account based API count cache size", null);
-
+ ApiLimitCacheSize("Advanced", ManagementServer.class, Integer.class, "api.throttling.cachesize", "50000", "Account based API count cache size", null),
+
+
+ // VMSnapshots
+ VMSnapshotMax("Advanced", VMSnapshotManager.class, Integer.class, "vmsnapshot.max", "10", "Maximum vm snapshots for a vm", null),
+ VMSnapshotCreateWait("Advanced", VMSnapshotManager.class, Integer.class, "vmsnapshot.create.wait", "600", "In second, timeout for create vm snapshot", null),
+ VMSnapshotExpungeInterval("Advanced", VMSnapshotManager.class, Integer.class, "vmsnapshot.expunge.interval", "60", "The interval (in seconds) to wait before running the expunge thread.", null),
+ VMSnapshotExpungeWorkers("Advanced", VMSnapshotManager.class, Integer.class, "vmsnapshot.expunge.workers", "1", "Number of workers performing expunge ", null);
+
+
private final String _category;
private final Class<?> _componentClass;
private final Class<?> _type;
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/9a12756a/server/src/com/cloud/server/ManagementServerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java
index 0943bfc..d381206 100755
--- a/server/src/com/cloud/server/ManagementServerImpl.java
+++ b/server/src/com/cloud/server/ManagementServerImpl.java
@@ -99,6 +99,10 @@ import org.apache.cloudstack.api.command.user.tag.*;
import org.apache.cloudstack.api.command.user.template.*;
import org.apache.cloudstack.api.command.user.vm.*;
import org.apache.cloudstack.api.command.user.vmgroup.*;
+import org.apache.cloudstack.api.command.user.vmsnapshot.CreateVMSnapshotCmd;
+import org.apache.cloudstack.api.command.user.vmsnapshot.DeleteVMSnapshotCmd;
+import org.apache.cloudstack.api.command.user.vmsnapshot.ListVMSnapshotCmd;
+import org.apache.cloudstack.api.command.user.vmsnapshot.RevertToSnapshotCmd;
import org.apache.cloudstack.api.command.user.volume.*;
import org.apache.cloudstack.api.command.user.vpc.*;
import org.apache.cloudstack.api.command.user.vpn.*;
@@ -2143,6 +2147,10 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
cmdList.add(ResetVpnConnectionCmd.class);
cmdList.add(UpdateVpnCustomerGatewayCmd.class);
cmdList.add(ListZonesByCmd.class);
+ cmdList.add(ListVMSnapshotCmd.class);
+ cmdList.add(CreateVMSnapshotCmd.class);
+ cmdList.add(RevertToSnapshotCmd.class);
+ cmdList.add(DeleteVMSnapshotCmd.class);
return cmdList;
}
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/9a12756a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
index c7beff0..e06da75 100755
--- a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
+++ b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
@@ -104,6 +104,9 @@ import org.apache.log4j.Logger;
import javax.ejb.Local;
import javax.naming.ConfigurationException;
import java.util.*;
+import com.cloud.vm.snapshot.VMSnapshot;
+import com.cloud.vm.snapshot.VMSnapshotVO;
+import com.cloud.vm.snapshot.dao.VMSnapshotDao;
@Component
@Local(value = { SnapshotManager.class, SnapshotService.class })
@@ -167,7 +170,9 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
private ResourceTagDao _resourceTagDao;
@Inject
private ConfigurationDao _configDao;
-
+ @Inject
+ private VMSnapshotDao _vmSnapshotDao;
+ String _name;
private int _totalRetries;
private int _pauseInterval;
private int _deltaSnapshotMax;
@@ -395,6 +400,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
}
// if volume is attached to a vm in destroyed or expunging state; disallow
+ // if volume is attached to a vm in taking vm snapshot; disallow
if (volume.getInstanceId() != null) {
UserVmVO userVm = _vmDao.findById(volume.getInstanceId());
if (userVm != null) {
@@ -408,6 +414,12 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
if(activeSnapshots.size() > 1)
throw new CloudRuntimeException("There is other active snapshot tasks on the instance to which the volume is attached, please try again later");
}
+ List<VMSnapshotVO> activeVMSnapshots = _vmSnapshotDao.listByInstanceId(userVm.getId(),
+ VMSnapshot.State.Creating, VMSnapshot.State.Reverting, VMSnapshot.State.Expunging);
+ if (activeVMSnapshots.size() > 0) {
+ throw new CloudRuntimeException(
+ "There is other active vm snapshot tasks on the instance to which the volume is attached, please try again later");
+ }
}
}
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/9a12756a/server/src/com/cloud/tags/TaggedResourceManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/tags/TaggedResourceManagerImpl.java b/server/src/com/cloud/tags/TaggedResourceManagerImpl.java
index e44343d..06756b6 100644
--- a/server/src/com/cloud/tags/TaggedResourceManagerImpl.java
+++ b/server/src/com/cloud/tags/TaggedResourceManagerImpl.java
@@ -73,6 +73,7 @@ import com.cloud.utils.db.Transaction;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.uuididentity.dao.IdentityDao;
import com.cloud.vm.dao.UserVmDao;
+import com.cloud.vm.snapshot.dao.VMSnapshotDao;
@Component
@@ -121,6 +122,8 @@ public class TaggedResourceManagerImpl extends ManagerBase implements TaggedReso
VpcDao _vpcDao;
@Inject
StaticRouteDao _staticRouteDao;
+ @Inject
+ VMSnapshotDao _vmSnapshotDao;
@Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
@@ -139,6 +142,7 @@ public class TaggedResourceManagerImpl extends ManagerBase implements TaggedReso
_daoMap.put(TaggedResourceType.Vpc, _vpcDao);
_daoMap.put(TaggedResourceType.NetworkACL, _firewallDao);
_daoMap.put(TaggedResourceType.StaticRoute, _staticRouteDao);
+ _daoMap.put(TaggedResourceType.VMSnapshot, _vmSnapshotDao);
return true;
}
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/9a12756a/server/src/com/cloud/vm/UserVmManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java
index d5c66de..19887ff 100644
--- a/server/src/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/com/cloud/vm/UserVmManagerImpl.java
@@ -249,12 +249,37 @@ import com.cloud.utils.exception.ExecutionException;
import com.cloud.utils.fsm.NoTransitionException;
import com.cloud.utils.net.NetUtils;
import com.cloud.vm.VirtualMachine.State;
+import com.cloud.vm.dao.*;
+import org.apache.cloudstack.acl.ControlledEntity.ACLType;
+import org.apache.cloudstack.acl.SecurityChecker.AccessType;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd;
+import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd;
+import org.apache.cloudstack.api.command.user.template.CreateTemplateCmd;
+import org.apache.cloudstack.api.command.user.vm.*;
+import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd;
+import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd;
+import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd;
+import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.log4j.Logger;
+
+import javax.ejb.Local;
+import javax.naming.ConfigurationException;
+import java.util.*;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
import com.cloud.vm.dao.InstanceGroupDao;
import com.cloud.vm.dao.InstanceGroupVMMapDao;
import com.cloud.vm.dao.NicDao;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.UserVmDetailsDao;
import com.cloud.vm.dao.VMInstanceDao;
+import com.cloud.vm.snapshot.VMSnapshot;
+import com.cloud.vm.snapshot.VMSnapshotManager;
+import com.cloud.vm.snapshot.VMSnapshotVO;
+import com.cloud.vm.snapshot.dao.VMSnapshotDao;
@Local(value = { UserVmManager.class, UserVmService.class })
public class UserVmManagerImpl extends ManagerBase implements UserVmManager, UserVmService {
@@ -392,7 +417,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
protected GuestOSCategoryDao _guestOSCategoryDao;
@Inject
UsageEventDao _usageEventDao;
-
+ @Inject
+ protected VMSnapshotDao _vmSnapshotDao;
+ @Inject
+ protected VMSnapshotManager _vmSnapshotMgr;
+
protected ScheduledExecutorService _executor = null;
protected int _expungeInterval;
protected int _expungeDelay;
@@ -813,7 +842,12 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
// permission check
_accountMgr.checkAccess(caller, null, true, volume, vm);
- // Check if volume is stored on secondary Storage.
+ //check if vm has snapshot, if true: can't attache volume
+ boolean attach = true;
+ checkVMSnapshots(vm, volumeId, attach);
+
+ // Check if volume is stored on secondary Storage.
+ //Check if volume is stored on secondary Storage.
boolean isVolumeOnSec = false;
VolumeHostVO volHostVO = _volumeHostDao.findByVolumeId(volume.getId());
if (volHostVO != null) {
@@ -1106,8 +1140,19 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
}
}
+ private void checkVMSnapshots(UserVmVO vm, Long volumeId, boolean attach) {
+ // Check that if vm has any VM snapshot
+ Long vmId = vm.getId();
+ List<VMSnapshotVO> listSnapshot = _vmSnapshotDao.listByInstanceId(vmId,
+ VMSnapshot.State.Ready, VMSnapshot.State.Creating, VMSnapshot.State.Reverting, VMSnapshot.State.Expunging);
+ if (listSnapshot != null && listSnapshot.size() != 0) {
+ throw new InvalidParameterValueException(
+ "The VM has VM snapshots, do not allowed to attach volume. Please delete the VM snapshots first.");
+ }
+ }
+
@Override
- @ActionEvent(eventType = EventTypes.EVENT_VOLUME_DETACH, eventDescription = "detaching volume", async = true)
+ @ActionEvent(eventType = EventTypes.EVENT_VOLUME_DETACH, eventDescription = "event_detaching_volume1", async = true)
public Volume detachVolumeFromVM(DetachVolumeCmd cmmd) {
Account caller = UserContext.current().getCaller();
if ((cmmd.getId() == null && cmmd.getDeviceId() == null && cmmd
@@ -1167,8 +1212,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
"Please specify a VM that is either running or stopped.");
}
- AsyncJobExecutor asyncExecutor = BaseAsyncJobExecutor
- .getCurrentExecutor();
+ // Check that if the volume has snapshot
+ boolean attach = false;
+ checkVMSnapshots(vm, volumeId, attach);
+ AsyncJobExecutor asyncExecutor = BaseAsyncJobExecutor.getCurrentExecutor();
if (asyncExecutor != null) {
AsyncJobVO job = asyncExecutor.getJob();
@@ -1314,12 +1361,25 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
throw new InvalidParameterValueException(
"unable to find a virtual machine with id " + vmId);
}
-
+
_accountMgr.checkAccess(caller, null, true, vmInstance);
// Check that the specified service offering ID is valid
_itMgr.checkIfCanUpgrade(vmInstance, svcOffId);
+ // remove diskAndMemory VM snapshots
+ List<VMSnapshotVO> vmSnapshots = _vmSnapshotDao.findByVm(vmId);
+ for (VMSnapshotVO vmSnapshotVO : vmSnapshots) {
+ if(vmSnapshotVO.getType() == VMSnapshot.Type.DiskAndMemory){
+ if(!_vmSnapshotMgr.deleteAllVMSnapshots(vmId, VMSnapshot.Type.DiskAndMemory)){
+ String errMsg = "Failed to remove VM snapshot during upgrading, snapshot id " + vmSnapshotVO.getId();
+ s_logger.debug(errMsg);
+ throw new CloudRuntimeException(errMsg);
+ }
+
+ }
+ }
+
_itMgr.upgradeVmDb(vmId, svcOffId);
return _vmDao.findById(vmInstance.getId());
@@ -1997,8 +2057,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
}
volume = _volsDao.findById(snapshot.getVolumeId());
- VolumeVO snapshotVolume = _volsDao
- .findByIdIncludingRemoved(snapshot.getVolumeId());
// check permissions
_accountMgr.checkAccess(caller, null, true, snapshot);