http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/33f690f1/setup/db/create-schema.sql ---------------------------------------------------------------------- diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index fa933e3..eded40d 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -2363,5 +2363,51 @@ CREATE TABLE `cloud`.`nicira_nvp_nic_map` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE `cloud`.`vm_snapshots` ( + `id` bigint(20) unsigned NOT NULL auto_increment COMMENT 'Primary Key', + `uuid` varchar(40) NOT NULL, + `snapshot_uuid` varchar(40) default NULL, + `name` varchar(255) NOT NULL, + `display_name` varchar(255) default NULL, + `description` varchar(255) default NULL, + `vm_id` bigint(20) unsigned NOT NULL, + `account_id` bigint(20) unsigned NOT NULL, + `service_offering_id` bigint(20) unsigned NOT NULL, + `domain_id` bigint(20) unsigned NOT NULL, + `memory` int(1) unsigned NOT NULL, + `state` varchar(32) NOT NULL, + `created` datetime default NULL, + `removed` datetime default NULL, + PRIMARY KEY (`id`), + CONSTRAINT UNIQUE KEY `uc_vm_snapshots_uuid` (`uuid`), + INDEX `vm_snapshots_name` (`name`), + INDEX `vm_snapshots_vm_id` (`vm_id`), + INDEX `vm_snapshots_account_id` (`account_id`), + INDEX `vm_snapshots_display_name` (`display_name`), + INDEX `vm_snapshots_removed` (`removed`), + CONSTRAINT `fk_vm_snapshots_vm_id__vm_instance_id` FOREIGN KEY `fk_vm_snapshots_vm_id__vm_instance_id` (`vm_id`) REFERENCES `vm_instance` (`id`), + CONSTRAINT `fk_vm_snapshots_account_id__account_id` FOREIGN KEY `fk_vm_snapshots_account_id__account_id` (`account_id`) REFERENCES `account` (`id`), + CONSTRAINT `fk_vm_snapshots_service_offering_id__service_offering_id` FOREIGN KEY `fk_vm_snapshots_service_offering_id__service_offering_id` (`service_offering_id`) REFERENCES `service_offering` (`id`), + CONSTRAINT `fk_vm_snapshots_domain_id__domain_id` FOREIGN KEY `fk_vm_snapshots_domain_id__domain_id` (`domain_id`) REFERENCES `domain` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `cloud`.`vm_snapshot_volume` ( + `id` bigint(20) unsigned NOT NULL auto_increment COMMENT 'Primary Key', + `uuid` varchar(40) NOT NULL, + `volume_path` varchar(255) default NULL, + `vm_snapshot_id` bigint(20) unsigned NOT NULL, + `snapshot_of` bigint(20) unsigned NOT NULL, + `volume_type` varchar(10) NOT NULL, + `created` datetime default NULL, + `removed` datetime default NULL, + PRIMARY KEY (`id`), + CONSTRAINT UNIQUE KEY `uc_vm_snapshot_volume_uuid` (`uuid`), + INDEX `i_vm_snapshot_volume__removed` (`removed`), + INDEX `i_vm_snapshot_volume__snapshot_of` (`snapshot_of`), + INDEX `i_vm_snapshot_volume__volume_type` (`volume_type`), + CONSTRAINT `fk_vm_snapshot_volume_id__vm_snapshots_id` FOREIGN KEY `fk_vm_snapshot_volume_id__vm_snapshots_id` (`vm_snapshot_id`) REFERENCES `vm_snapshots` (`id`), + CONSTRAINT `fk_vm_snapshot_snapshot_of__volumes_id` FOREIGN KEY `fk_vm_snapshot_snapshot_of__volumes_id` (`snapshot_of`) REFERENCES `volumes` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + SET foreign_key_checks = 1;
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/33f690f1/ui/index.jsp ---------------------------------------------------------------------- diff --git a/ui/index.jsp b/ui/index.jsp index 7a5489c..203c426 100644 --- a/ui/index.jsp +++ b/ui/index.jsp @@ -1637,6 +1637,7 @@ under the License. <script type="text/javascript" src="scripts/ui-custom/zoneWizard.js?t=<%=now%>"></script> <script type="text/javascript" src="scripts/system.js?t=<%=now%>"></script> <script type="text/javascript" src="scripts/domains.js?t=<%=now%>"></script> + <script type="text/javascript" src="scripts/vm_snapshots.js?t=<%=now%>"></script> </body> </html> <jsp:include page="dictionary.jsp" /> http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/33f690f1/ui/scripts/instances.js ---------------------------------------------------------------------- diff --git a/ui/scripts/instances.js b/ui/scripts/instances.js index 345f456..0f0d0f4 100644 --- a/ui/scripts/instances.js +++ b/ui/scripts/instances.js @@ -205,6 +205,7 @@ poll: pollAsyncJobResult } }, + destroy: { label: 'label.action.destroy.instance', messages: { @@ -317,7 +318,7 @@ detailView: { name: 'Instance details', - viewAll: { path: 'storage.volumes', label: 'label.volumes' }, + viewAll: [{ path: 'storage.volumes', label: 'label.volumes' }, { path: 'vmsnapshots', label: 'VM Snapshots' } ], tabFilter: function(args) { var hiddenTabs = []; var zoneNetworktype; @@ -485,6 +486,71 @@ poll: pollAsyncJobResult } }, + + snapshot: { + messages: { + notification: function(args) { + return 'label.action.take.snapshot'; + } + }, + label: 'label.action.take.snapshot', + addRow: 'false', + createForm: { + title: 'label.action.take.snapshot', + fields: { + name: { + label: 'label.name', + isInput: true + }, + description: { + label: 'label.description', + isTextarea: true + }, + snapshotMemory: { + label: 'snapshot.memory', + isBoolean: true, + isChecked: false + } + } + }, + action: function(args) { + //hongtu + var array1 = []; + array1.push("&snapshotmemory=" + (args.data.snapshotMemory == "on")); + var displayname = args.data.name; + if (displayname != null && displayname.length > 0) { + array1.push("&name=" + todb(displayname)); + } + var description = args.data.description; + if (description != null && description.length > 0) { + array1.push("&description=" + todb(description)); + } + $.ajax({ + url: createURL("createVMSnapshot&vmId=" + args.context.instances[0].id + array1.join("")), + dataType: "json", + async: true, + success: function(json) { + var jid = json.createvmsnapshotresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function(json) { + return json.queryasyncjobresultresponse.jobresult.virtualmachine; + }, + getActionFilter: function() { + return vmActionfilter; + } + } + }); + } + }); + + }, + notification: { + pool: pollAsyncJobResult + } + }, + destroy: { label: 'label.action.destroy.instance', messages: { @@ -1281,6 +1347,7 @@ else if (jsonObj.state == 'Running') { allowedActions.push("stop"); allowedActions.push("restart"); + allowedActions.push("snapshot"); allowedActions.push("destroy"); allowedActions.push("changeService"); @@ -1304,7 +1371,7 @@ allowedActions.push("edit"); allowedActions.push("start"); allowedActions.push("destroy"); - + allowedActions.push("snapshot"); if(isAdmin()) allowedActions.push("migrateToAnotherStorage"); http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/33f690f1/ui/scripts/ui/widgets/detailView.js ---------------------------------------------------------------------- diff --git a/ui/scripts/ui/widgets/detailView.js b/ui/scripts/ui/widgets/detailView.js index fc2ae45..00d3188 100644 --- a/ui/scripts/ui/widgets/detailView.js +++ b/ui/scripts/ui/widgets/detailView.js @@ -850,14 +850,20 @@ $actions.prependTo($firstRow.closest('div.detail-group').closest('.details')); } if (detailViewArgs.viewAll && showViewAll) { + + if( !(detailViewArgs.viewAll instanceof Array)){ + detailViewArgs.viewAll = [detailViewArgs.viewAll]; + } + $.each(detailViewArgs.viewAll, function(n, view){ $('<div>') .addClass('view-all') .append( $('<a>') .attr({ href: '#' }) - .data('detail-view-link-view-all', detailViewArgs.viewAll) + .css('padding','0 1px') + .data('detail-view-link-view-all', view) .append( - $('<span>').html(_l('label.view') + ' ' + _l(detailViewArgs.viewAll.label)) + $('<span>').html(_l('label.view') + ' ' + _l(view.label)) ) ) .append( @@ -866,9 +872,10 @@ .appendTo( $('<td>') .addClass('view-all') + .css('padding','9px 3px 8px 0') .appendTo($actions.find('tr')) ); - + }); } } http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/33f690f1/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostMO.java ---------------------------------------------------------------------- diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostMO.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostMO.java index 3557048..2946620 100755 --- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostMO.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostMO.java @@ -58,6 +58,8 @@ import com.vmware.vim25.PropertySpec; import com.vmware.vim25.SelectionSpec; import com.vmware.vim25.TraversalSpec; import com.vmware.vim25.VirtualMachineConfigSpec; +import com.vmware.vim25.VirtualMachineSnapshotInfo; +import com.vmware.vim25.VirtualMachineSnapshotTree; import com.vmware.vim25.VirtualNicManagerNetConfig; import com.vmware.vim25.NasDatastoreInfo; @@ -952,4 +954,20 @@ public class HostMO extends BaseMO implements VmwareHypervisorHost { HostRuntimeInfo runtimeInfo = (HostRuntimeInfo)_context.getServiceUtil().getDynamicProperty(_mor, "runtime"); return runtimeInfo.getConnectionState() == HostSystemConnectionState.connected; } + + public boolean revertToSnapshot(ManagedObjectReference morSnapshot) + throws Exception { + ManagedObjectReference morTask = _context.getService() + .revertToSnapshot_Task(morSnapshot, _mor, false); + String result = _context.getServiceUtil().waitForTask(morTask); + if (result.equals("sucess")) { + _context.waitForTaskProgressDone(morTask); + return true; + } else { + s_logger.error("VMware revert to snapshot failed due to " + + TaskMO.getTaskFailureInfo(_context, morTask)); + } + + return false; + } } http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/33f690f1/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java ---------------------------------------------------------------------- diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java index cd54127..d36814d 100644 --- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java @@ -405,6 +405,26 @@ public class VirtualMachineMO extends BaseMO { return false; } + public boolean revertToSnapshot(String snapshotName) throws Exception { + ManagedObjectReference morSnapshot = getSnapshotMor(snapshotName); + if (morSnapshot == null) { + s_logger.warn("Unable to find snapshot: " + snapshotName); + return false; + } + ManagedObjectReference morTask = _context.getService() + .revertToSnapshot_Task(morSnapshot, _mor, null); + String result = _context.getServiceUtil().waitForTask(morTask); + if (result.equals("sucess")) { + _context.waitForTaskProgressDone(morTask); + return true; + } else { + s_logger.error("VMware revert to snapshot failed due to " + + TaskMO.getTaskFailureInfo(_context, morTask)); + } + + return false; + } + public boolean removeAllSnapshots() throws Exception { VirtualMachineSnapshotInfo snapshotInfo = getSnapshotInfo();
