cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From raj...@apache.org
Subject [1/4] git commit: updated refs/heads/master to 7233ac3
Date Tue, 31 Jan 2017 00:31:16 GMT
Repository: cloudstack
Updated Branches:
  refs/heads/master f10c8bfe0 -> 7233ac37c


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a2428508/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java b/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java
index bb1536d..d155186 100644
--- a/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java
+++ b/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java
@@ -33,6 +33,8 @@ import org.apache.cloudstack.context.CallContext;
 import org.apache.cloudstack.engine.subsystem.api.storage.StorageStrategyFactory;
 import org.apache.cloudstack.engine.subsystem.api.storage.VMSnapshotOptions;
 import org.apache.cloudstack.engine.subsystem.api.storage.VMSnapshotStrategy;
+import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
+import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
 import org.apache.cloudstack.framework.config.ConfigKey;
 import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
 import org.apache.cloudstack.framework.jobs.AsyncJob;
@@ -44,8 +46,11 @@ import org.apache.cloudstack.framework.jobs.impl.AsyncJobVO;
 import org.apache.cloudstack.framework.jobs.impl.OutcomeImpl;
 import org.apache.cloudstack.framework.jobs.impl.VmWorkJobVO;
 import org.apache.cloudstack.jobs.JobInfo;
+import org.apache.cloudstack.storage.to.VolumeObjectTO;
 import org.apache.cloudstack.utils.identity.ManagementServerNode;
 
+import com.cloud.agent.api.RestoreVMSnapshotCommand;
+import com.cloud.agent.api.VMSnapshotTO;
 import com.cloud.api.query.MutualExclusiveIdsManagerBase;
 import com.cloud.event.ActionEvent;
 import com.cloud.event.EventTypes;
@@ -59,8 +64,10 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao;
 import com.cloud.projects.Project.ListProjectResourcesCriteria;
 import com.cloud.service.dao.ServiceOfferingDetailsDao;
+import com.cloud.storage.GuestOSVO;
 import com.cloud.storage.Snapshot;
 import com.cloud.storage.SnapshotVO;
+import com.cloud.storage.Storage.ImageFormat;
 import com.cloud.storage.Volume;
 import com.cloud.storage.Volume.Type;
 import com.cloud.storage.VolumeVO;
@@ -119,7 +126,8 @@ public class VMSnapshotManagerImpl extends MutualExclusiveIdsManagerBase
impleme
     @Inject HypervisorCapabilitiesDao _hypervisorCapabilitiesDao;
     @Inject
     StorageStrategyFactory storageStrategyFactory;
-
+    @Inject
+    VolumeDataFactory volumeDataFactory;
     @Inject
     EntityManager _entityMgr;
     @Inject
@@ -263,7 +271,7 @@ public class VMSnapshotManagerImpl extends MutualExclusiveIdsManagerBase
impleme
             throw new InvalidParameterValueException("Creating VM snapshot failed due to
VM:" + vmId + " is a system VM or does not exist");
         }
 
-        if (_snapshotDao.listByInstanceId(vmId, Snapshot.State.BackedUp).size() > 0) {
+        if (_snapshotDao.listByInstanceId(vmId, Snapshot.State.BackedUp).size() > 0 &&
! HypervisorType.KVM.equals(userVmVo.getHypervisorType())) {
             throw new InvalidParameterValueException(
                     "VM snapshot for this VM is not allowed. This VM has volumes attached
which has snapshots, please remove all snapshots before taking VM snapshot");
         }
@@ -298,8 +306,8 @@ public class VMSnapshotManagerImpl extends MutualExclusiveIdsManagerBase
impleme
             throw new InvalidParameterValueException("Creating vm snapshot failed due to
VM:" + vmId + " is not in the running or Stopped state");
         }
 
-        if(snapshotMemory && userVmVo.getState() == VirtualMachine.State.Stopped){
-            throw new InvalidParameterValueException("Can not snapshot memory when VM is
in stopped state");
+        if(snapshotMemory && userVmVo.getState() != VirtualMachine.State.Running){
+            throw new InvalidParameterValueException("Can not snapshot memory when VM is
not in Running state");
         }
 
         // for KVM, only allow snapshot with memory when VM is in running state
@@ -323,6 +331,9 @@ public class VMSnapshotManagerImpl extends MutualExclusiveIdsManagerBase
impleme
             if (activeSnapshots.size() > 0) {
                 throw new CloudRuntimeException("There is other active volume snapshot tasks
on the instance to which the volume is attached, please try again later.");
             }
+            if (userVmVo.getHypervisorType() == HypervisorType.KVM && volume.getFormat()
!= ImageFormat.QCOW2) {
+                throw new CloudRuntimeException("We only support create vm snapshots from
vm with QCOW2 image");
+            }
         }
 
         // check if there are other active VM snapshot tasks
@@ -367,7 +378,7 @@ public class VMSnapshotManagerImpl extends MutualExclusiveIdsManagerBase
impleme
 
     @Override
     @ActionEvent(eventType = EventTypes.EVENT_VM_SNAPSHOT_CREATE, eventDescription = "creating
VM snapshot", async = true)
-    public VMSnapshot creatVMSnapshot(Long vmId, Long vmSnapshotId, Boolean quiescevm) {
+    public VMSnapshot createVMSnapshot(Long vmId, Long vmSnapshotId, Boolean quiescevm) {
         UserVmVO userVm = _userVMDao.findById(vmId);
         if (userVm == null) {
             throw new InvalidParameterValueException("Create vm to snapshot failed due to
vm: " + vmId + " is not found");
@@ -718,6 +729,40 @@ public class VMSnapshotManagerImpl extends MutualExclusiveIdsManagerBase
impleme
     }
 
     @Override
+    public RestoreVMSnapshotCommand createRestoreCommand(UserVmVO userVm, List<VMSnapshotVO>
vmSnapshotVOs) {
+        if (!HypervisorType.KVM.equals(userVm.getHypervisorType()))
+            return null;
+
+        List<VMSnapshotTO> snapshots = new ArrayList<VMSnapshotTO>();
+        Map<Long, VMSnapshotTO> snapshotAndParents = new HashMap<Long, VMSnapshotTO>();
+        for (VMSnapshotVO vmSnapshotVO: vmSnapshotVOs) {
+            if (vmSnapshotVO.getType() == VMSnapshot.Type.DiskAndMemory) {
+                VMSnapshotVO snapshot = _vmSnapshotDao.findById(vmSnapshotVO.getId());
+                VMSnapshotTO parent = getSnapshotWithParents(snapshot).getParent();
+                VMSnapshotOptions options = snapshot.getOptions();
+                boolean quiescevm = true;
+                if (options != null)
+                    quiescevm = options.needQuiesceVM();
+                VMSnapshotTO vmSnapshotTO = new VMSnapshotTO(snapshot.getId(), snapshot.getName(),
snapshot.getType(),
+                        snapshot.getCreated().getTime(), snapshot.getDescription(), snapshot.getCurrent(),
parent, quiescevm);
+                snapshots.add(vmSnapshotTO);
+                snapshotAndParents.put(vmSnapshotVO.getId(), parent);
+            }
+        }
+        if (snapshotAndParents.isEmpty())
+            return null;
+
+        // prepare RestoreVMSnapshotCommand
+        String vmInstanceName = userVm.getInstanceName();
+        List<VolumeObjectTO> volumeTOs = getVolumeTOList(userVm.getId());
+        GuestOSVO guestOS = _guestOSDao.findById(userVm.getGuestOSId());
+        RestoreVMSnapshotCommand restoreSnapshotCommand = new RestoreVMSnapshotCommand(vmInstanceName,
null, volumeTOs, guestOS.getDisplayName());
+        restoreSnapshotCommand.setSnapshots(snapshots);
+        restoreSnapshotCommand.setSnapshotAndParents(snapshotAndParents);
+        return restoreSnapshotCommand;
+    }
+
+    @Override
     public VMSnapshot getVMSnapshotById(Long id) {
         VMSnapshotVO vmSnapshot = _vmSnapshotDao.findById(id);
         return vmSnapshot;
@@ -1050,4 +1095,42 @@ public class VMSnapshotManagerImpl extends MutualExclusiveIdsManagerBase
impleme
 
         return workJob;
     }
+
+    private List<VolumeObjectTO> getVolumeTOList(Long vmId) {
+        List<VolumeObjectTO> volumeTOs = new ArrayList<VolumeObjectTO>();
+        List<VolumeVO> volumeVos = _volumeDao.findByInstance(vmId);
+        VolumeInfo volumeInfo = null;
+        for (VolumeVO volume : volumeVos) {
+            volumeInfo = volumeDataFactory.getVolume(volume.getId());
+
+            volumeTOs.add((VolumeObjectTO)volumeInfo.getTO());
+        }
+        return volumeTOs;
+    }
+
+    private VMSnapshotTO convert2VMSnapshotTO(VMSnapshotVO vo) {
+        return new VMSnapshotTO(vo.getId(), vo.getName(), vo.getType(), vo.getCreated().getTime(),
vo.getDescription(), vo.getCurrent(), null, true);
+    }
+
+    private VMSnapshotTO getSnapshotWithParents(VMSnapshotVO snapshot) {
+        Map<Long, VMSnapshotVO> snapshotMap = new HashMap<Long, VMSnapshotVO>();
+        List<VMSnapshotVO> allSnapshots = _vmSnapshotDao.findByVm(snapshot.getVmId());
+        for (VMSnapshotVO vmSnapshotVO : allSnapshots) {
+            snapshotMap.put(vmSnapshotVO.getId(), vmSnapshotVO);
+        }
+
+        VMSnapshotTO currentTO = convert2VMSnapshotTO(snapshot);
+        VMSnapshotTO result = currentTO;
+        VMSnapshotVO current = snapshot;
+        while (current.getParent() != null) {
+            VMSnapshotVO parent = snapshotMap.get(current.getParent());
+            if (parent == null) {
+                break;
+            }
+            currentTO.setParent(convert2VMSnapshotTO(parent));
+            current = snapshotMap.get(current.getParent());
+            currentTO = currentTO.getParent();
+        }
+        return result;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a2428508/server/test/com/cloud/storage/snapshot/SnapshotManagerTest.java
----------------------------------------------------------------------
diff --git a/server/test/com/cloud/storage/snapshot/SnapshotManagerTest.java b/server/test/com/cloud/storage/snapshot/SnapshotManagerTest.java
index 7f0f71b..58ee2e7 100644
--- a/server/test/com/cloud/storage/snapshot/SnapshotManagerTest.java
+++ b/server/test/com/cloud/storage/snapshot/SnapshotManagerTest.java
@@ -56,6 +56,8 @@ import org.apache.cloudstack.engine.subsystem.api.storage.StorageStrategyFactory
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
+import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
+import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
 import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
 import org.junit.After;
 import org.junit.Assert;
@@ -89,6 +91,8 @@ public class SnapshotManagerTest {
     @Mock
     VMSnapshotDao _vmSnapshotDao;
     @Mock
+    VMSnapshotVO vmSnapshotMock;
+    @Mock
     Account account;
     @Mock
     UserVmVO vmMock;
@@ -118,11 +122,16 @@ public class SnapshotManagerTest {
     ResourceManager _resourceMgr;
     @Mock
     DataStore storeMock;
+    @Mock
+    SnapshotDataStoreDao _snapshotStoreDao;
+    @Mock
+    SnapshotDataStoreVO snapshotStoreMock;
 
     private static final long TEST_SNAPSHOT_ID = 3L;
     private static final long TEST_VOLUME_ID = 4L;
     private static final long TEST_VM_ID = 5L;
     private static final long TEST_STORAGE_POOL_ID = 6L;
+    private static final long TEST_VM_SNAPSHOT_ID = 6L;
 
     @Before
     public void setup() throws ResourceAllocationException {
@@ -138,6 +147,7 @@ public class SnapshotManagerTest {
         _snapshotMgr._storagePoolDao = _storagePoolDao;
         _snapshotMgr._resourceMgr = _resourceMgr;
         _snapshotMgr._vmSnapshotDao = _vmSnapshotDao;
+        _snapshotMgr._snapshotStoreDao = _snapshotStoreDao;
 
         when(_snapshotDao.findById(anyLong())).thenReturn(snapshotMock);
         when(snapshotMock.getVolumeId()).thenReturn(TEST_VOLUME_ID);
@@ -147,9 +157,11 @@ public class SnapshotManagerTest {
         when(volumeMock.getState()).thenReturn(Volume.State.Ready);
         when(volumeFactory.getVolume(anyLong())).thenReturn(volumeInfoMock);
         when(volumeInfoMock.getDataStore()).thenReturn(storeMock);
+        when(volumeInfoMock.getState()).thenReturn(Volume.State.Ready);
         when(storeMock.getId()).thenReturn(TEST_STORAGE_POOL_ID);
 
         when(snapshotFactory.getSnapshot(anyLong(), Mockito.any(DataStoreRole.class))).thenReturn(snapshotInfoMock);
+        when(_storageStrategyFactory.getSnapshotStrategy(Mockito.any(SnapshotVO.class), Mockito.eq(SnapshotOperation.BACKUP))).thenReturn(snapshotStrategy);
         when(_storageStrategyFactory.getSnapshotStrategy(Mockito.any(SnapshotVO.class), Mockito.eq(SnapshotOperation.REVERT))).thenReturn(snapshotStrategy);
         when(_storageStrategyFactory.getSnapshotStrategy(Mockito.any(SnapshotVO.class), Mockito.eq(SnapshotOperation.DELETE))).thenReturn(snapshotStrategy);
 
@@ -278,4 +290,46 @@ public class SnapshotManagerTest {
         Snapshot snapshot = _snapshotMgr.revertSnapshot(TEST_SNAPSHOT_ID);
         Assert.assertNotNull(snapshot);
     }
+
+    // vm on Xenserver, expected exception
+    @Test(expected = InvalidParameterValueException.class)
+    public void testBackupSnapshotFromVmSnapshotF1() {
+        when(_vmDao.findById(anyLong())).thenReturn(vmMock);
+        when(vmMock.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.XenServer);
+        Snapshot snapshot = _snapshotMgr.backupSnapshotFromVmSnapshot(TEST_SNAPSHOT_ID, TEST_VM_ID,
TEST_VOLUME_ID, TEST_VM_SNAPSHOT_ID);
+        Assert.assertNull(snapshot);
+    }
+
+    // vm on KVM, first time
+    @Test
+    public void testBackupSnapshotFromVmSnapshotF2() {
+        when(_vmDao.findById(anyLong())).thenReturn(vmMock);
+        when(vmMock.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM);
+        when(_vmSnapshotDao.findById(anyLong())).thenReturn(vmSnapshotMock);
+        when(_snapshotStoreDao.findParent(any(DataStoreRole.class), anyLong(), anyLong())).thenReturn(null);
+        when(snapshotFactory.getSnapshot(anyLong(), Mockito.any(DataStore.class))).thenReturn(snapshotInfoMock);
+        when(storeMock.create(snapshotInfoMock)).thenReturn(snapshotInfoMock);
+        when(_snapshotStoreDao.findBySnapshot(anyLong(), any(DataStoreRole.class))).thenReturn(snapshotStoreMock);
+        when(_snapshotStoreDao.update(anyLong(), any(SnapshotDataStoreVO.class))).thenReturn(true);
+        when(_snapshotDao.update(anyLong(), any(SnapshotVO.class))).thenReturn(true);
+        when(vmMock.getAccountId()).thenReturn(2L);
+        when(snapshotStrategy.backupSnapshot(any(SnapshotInfo.class))).thenReturn(snapshotInfoMock);;;
+
+        Snapshot snapshot = _snapshotMgr.backupSnapshotFromVmSnapshot(TEST_SNAPSHOT_ID, TEST_VM_ID,
TEST_VOLUME_ID, TEST_VM_SNAPSHOT_ID);
+        Assert.assertNotNull(snapshot);
+    }
+
+    // vm on KVM, already backed up
+    @Test(expected = InvalidParameterValueException.class)
+    public void testBackupSnapshotFromVmSnapshotF3() {
+        when(_vmDao.findById(anyLong())).thenReturn(vmMock);
+        when(vmMock.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM);
+        when(_vmSnapshotDao.findById(anyLong())).thenReturn(vmSnapshotMock);
+        when(_snapshotStoreDao.findParent(any(DataStoreRole.class), anyLong(), anyLong())).thenReturn(snapshotStoreMock);
+        when(snapshotStoreMock.getInstallPath()).thenReturn("VM_SNAPSHOT_NAME");
+        when(vmSnapshotMock.getName()).thenReturn("VM_SNAPSHOT_NAME");
+        Snapshot snapshot = _snapshotMgr.backupSnapshotFromVmSnapshot(TEST_SNAPSHOT_ID, TEST_VM_ID,
TEST_VOLUME_ID, TEST_VM_SNAPSHOT_ID);
+        Assert.assertNull(snapshot);
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a2428508/setup/db/db/schema-4920to41000.sql
----------------------------------------------------------------------
diff --git a/setup/db/db/schema-4920to41000.sql b/setup/db/db/schema-4920to41000.sql
index ef1a63c..b8b54e3 100644
--- a/setup/db/db/schema-4920to41000.sql
+++ b/setup/db/db/schema-4920to41000.sql
@@ -53,3 +53,12 @@ ALTER TABLE `cloud`.`image_store_details` CHANGE COLUMN `value` `value`
VARCHAR(
 NULL DEFAULT '1' COMMENT 'True if the detail can be displayed to the end user' AFTER `value`;
 
 ALTER TABLE `snapshots` ADD COLUMN `location_type` VARCHAR(32) COMMENT 'Location of snapshot
(ex. Primary)';
+
+-- Database change for CLOUDSTACK-8746 (VM Snapshotting implementation for KVM)
+UPDATE `cloud`.`hypervisor_capabilities` SET `vm_snapshot_enabled` = 1 WHERE `hypervisor_type`
='KVM' AND `hypervisor_version` = 'default';
+
+-- [VM-SNAPSHOT] add role permissions for new API command createSnapshotFromVMSnapshot
+INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`)
values (UUID(), 2, 'createSnapshotFromVMSnapshot', 'ALLOW', 318) ON DUPLICATE KEY UPDATE rule=rule;
+INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`)
values (UUID(), 3, 'createSnapshotFromVMSnapshot', 'ALLOW', 302) ON DUPLICATE KEY UPDATE rule=rule;
+INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`)
values (UUID(), 4, 'createSnapshotFromVMSnapshot', 'ALLOW', 260) ON DUPLICATE KEY UPDATE rule=rule;
+

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a2428508/test/integration/smoke/test_vm_snapshots.py
----------------------------------------------------------------------
diff --git a/test/integration/smoke/test_vm_snapshots.py b/test/integration/smoke/test_vm_snapshots.py
index 5fcb80a..31b6822 100644
--- a/test/integration/smoke/test_vm_snapshots.py
+++ b/test/integration/smoke/test_vm_snapshots.py
@@ -42,7 +42,7 @@ class TestVmSnapshot(cloudstackTestCase):
         cls._cleanup = []
         cls.unsupportedHypervisor = False
         cls.hypervisor = testClient.getHypervisorInfo()
-        if cls.hypervisor.lower() in (KVM.lower(), "hyperv", "lxc"):
+        if cls.hypervisor.lower() in ("hyperv", "lxc"):
             cls.unsupportedHypervisor = True
             return
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a2428508/ui/css/cloudstack3.css
----------------------------------------------------------------------
diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css
index 16ee0b7..950c22a 100644
--- a/ui/css/cloudstack3.css
+++ b/ui/css/cloudstack3.css
@@ -2830,6 +2830,10 @@ div.detail-group.actions td {
   background-position: -82px -686px;
 }
 
+#navigation ul li.vmsnapshots span.icon {
+  background: url(../images/sprites.png) no-repeat -34px -666px;
+}
+
 #navigation ul li.affinityGroups span.icon {
   background-position: -73px -87px;
 }
@@ -12822,6 +12826,7 @@ div.ui-dialog div.autoscaler div.field-group div.form-container form
div.form-it
 }
 
 .revertSnapshot .icon,
+.revertToVMSnapshot .icon,
 .restoreVM .icon,
 .restore .icon,
 .recover .icon {
@@ -12838,6 +12843,7 @@ div.ui-dialog div.autoscaler div.field-group div.form-container form
div.form-it
 }
 
 .revertSnapshot:hover .icon,
+.revertToVMSnapshot:hover .icon,
 .restoreVM:hover .icon,
 .restore:hover .icon {
   background-position: -168px -613px;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a2428508/ui/l10n/en.js
----------------------------------------------------------------------
diff --git a/ui/l10n/en.js b/ui/l10n/en.js
index 075a0d8..f6669ca 100644
--- a/ui/l10n/en.js
+++ b/ui/l10n/en.js
@@ -1865,6 +1865,7 @@ var dictionary = {"ICMP.code":"ICMP Code",
 "message.action.stop.systemvm":"Please confirm that you want to stop this system VM.",
 "message.action.take.snapshot":"Please confirm that you want to take a snapshot of this volume.",
 "message.action.unmanage.cluster":"Please confirm that you want to unmanage the cluster.",
+"message.action.vmsnapshot.create":"Please confirm that you want to take a snapshot of this
instance. <br>Please notice that the instance will be paused during the snapshoting,
and resumed after snapshotting, if it runs on KVM.",
 "message.action.vmsnapshot.delete":"Please confirm that you want to delete this VM snapshot.",
 "message.action.vmsnapshot.revert":"Revert VM snapshot",
 "message.activate.project":"Are you sure you want to activate this project?",
@@ -2281,4 +2282,4 @@ var dictionary = {"ICMP.code":"ICMP Code",
 "state.detached":"Detached",
 "title.upload.volume":"Upload Volume",
 "ui.listView.filters.all":"All",
-"ui.listView.filters.mine":"Mine"};
\ No newline at end of file
+"ui.listView.filters.mine":"Mine"};

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a2428508/ui/scripts/instances.js
----------------------------------------------------------------------
diff --git a/ui/scripts/instances.js b/ui/scripts/instances.js
index 19db257..ad70fc2 100644
--- a/ui/scripts/instances.js
+++ b/ui/scripts/instances.js
@@ -28,6 +28,7 @@
             addRow: 'false',
             createForm: {
                 title: 'label.action.vmsnapshot.create',
+                desc: 'message.action.vmsnapshot.create',
                 fields: {
                     name: {
                         label: 'label.name',
@@ -423,7 +424,7 @@
                     path: 'storage.volumes',
                     label: 'label.volumes'
                 }, {
-                    path: 'vmsnapshots',
+                    path: 'storage.vmsnapshots',
                     label: 'label.snapshots'
                 }, {
                     path: 'affinityGroups',
@@ -2701,8 +2702,7 @@
             allowedActions.push("stop");
             allowedActions.push("restart");
 
-            if ((jsonObj.hypervisor != 'KVM' || g_kvmsnapshotenabled == true)
-                    && (jsonObj.hypervisor != 'LXC')) {
+            if (jsonObj.hypervisor != 'LXC') {
                 allowedActions.push("snapshot");
             }
 
@@ -2738,8 +2738,7 @@
             allowedActions.push("destroy");
             allowedActions.push("reinstall");
 
-            if ((jsonObj.hypervisor != 'KVM' || g_kvmsnapshotenabled == true)
-                    && (jsonObj.hypervisor != 'LXC')) {
+            if (jsonObj.hypervisor != 'KVM' && jsonObj.hypervisor != 'LXC') {
                 allowedActions.push("snapshot");
             }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a2428508/ui/scripts/storage.js
----------------------------------------------------------------------
diff --git a/ui/scripts/storage.js b/ui/scripts/storage.js
index b26e60b..0f51f31 100644
--- a/ui/scripts/storage.js
+++ b/ui/scripts/storage.js
@@ -2330,7 +2330,350 @@
                             }
                         }
                     }
-                }
+                },
+            },
+
+            /**
+             * VM Snapshots
+             */
+            vmsnapshots: {
+                type: 'select',
+		title: 'label.vmsnapshot',
+		listView: {
+		    id: 'vmsnapshots',
+		    isMaximized: true,
+		    fields: {
+		        displayname: {
+		            label: 'label.name'
+		        },
+		        state: {
+		            label: 'label.state',
+		            indicator: {
+		                'Ready': 'on',
+		                'Error': 'off'
+		            }
+		        },
+		        type: {
+		            label: 'label.vmsnapshot.type'
+		        },
+		        current: {
+		            label: 'label.vmsnapshot.current',
+		            converter: cloudStack.converters.toBooleanText
+		        },
+		        parentName: {
+		            label: 'label.vmsnapshot.parentname'
+		        },
+		        created: {
+		            label: 'label.date',
+		            converter: cloudStack.converters.toLocalDate
+		        }
+		    },
+
+                    advSearchFields: {
+                        name: {
+                            label: 'label.name'
+                        },
+
+                        domainid: {
+                            label: 'label.domain',
+                            select: function(args) {
+                                if (isAdmin() || isDomainAdmin()) {
+                                    $.ajax({
+                                        url: createURL('listDomains'),
+                                        data: {
+                                            listAll: true,
+                                            details: 'min'
+                                        },
+                                        success: function(json) {
+                                            var array1 = [{
+                                                id: '',
+                                                description: ''
+                                            }];
+                                            var domains = json.listdomainsresponse.domain;
+                                            if (domains != null && domains.length
> 0) {
+                                                for (var i = 0; i < domains.length; i++)
{
+                                                    array1.push({
+                                                        id: domains[i].id,
+                                                        description: domains[i].path
+                                                    });
+                                                }
+                                            }
+                                            array1.sort(function(a, b) {
+                                                return a.description.localeCompare(b.description);
+                                            });
+                                            args.response.success({
+                                                data: array1
+                                            });
+                                        }
+                                    });
+                                } else {
+                                    args.response.success({
+                                        data: null
+                                    });
+                                }
+                            },
+                            isHidden: function(args) {
+                                if (isAdmin() || isDomainAdmin())
+                                    return false;
+                                else
+                                    return true;
+                            }
+                        },
+
+                        account: {
+                            label: 'label.account',
+                            isHidden: function(args) {
+                                if (isAdmin() || isDomainAdmin())
+                                    return false;
+                                else
+                                    return true;
+                            }
+                        },
+                        tagKey: {
+                            label: 'label.tag.key'
+                        },
+                        tagValue: {
+                            label: 'label.tag.value'
+                        }
+                    },
+
+		    dataProvider: function(args) {
+                        var data = {};
+                        listViewDataProvider(args, data);
+
+		        if (args.context != null) {
+		            if ("instances" in args.context) {
+                                $.extend(data, {
+                                    virtualMachineId: args.context.instances[0].id
+                                });
+		            }
+		        }
+		        $.ajax({
+		            url: createURL('listVMSnapshot&listAll=true'),
+                            data: data,
+		            dataType: "json",
+		            async: true,
+		            success: function(json) {
+		                var jsonObj;
+		                jsonObj = json.listvmsnapshotresponse.vmSnapshot;
+		                args.response.success({
+                                    actionFilter: vmSnapshotActionfilter,
+		                    data: jsonObj
+		                });
+		            }
+		        });
+		    },
+		    //dataProvider end
+		    detailView: {
+		        tabs: {
+		            details: {
+		                title: 'label.details',
+		                fields: {
+		                    id: {
+		                        label: 'label.id'
+		                    },
+		                    name: {
+		                        label: 'label.name'
+		                    },
+		                    displayname: {
+		                        label: 'label.display.name'
+		                    },
+		                    type: {
+		                        label: 'label.vmsnapshot.type'
+		                    },
+		                    description: {
+		                        label: 'label.description'
+		                    },
+		                    state: {
+		                        label: 'label.state',
+		                        indicator: {
+		                            'Ready': 'on',
+		                            'Error': 'off'
+		                        }
+		                    },
+		                    current: {
+		                        label: 'label.vmsnapshot.current',
+		                        converter: cloudStack.converters.toBooleanText
+		                    },
+		                    parentName: {
+		                        label: 'label.vmsnapshot.parentname'
+		                    },
+                                    domain: {
+                                        label: 'label.domain'
+                                    },
+                                    account: {
+                                        label: 'label.account'
+                                    },
+                                    virtualmachineid: {
+                                        label: 'label.vm.id'
+                                    },
+		                    created: {
+		                        label: 'label.date',
+		                        converter: cloudStack.converters.toLocalDate
+		                    }
+		                },
+		                dataProvider: function(args) {
+		                    $.ajax({
+		                        url: createURL("listVMSnapshot&listAll=true&vmsnapshotid="
+ args.context.vmsnapshots[0].id),
+		                        dataType: "json",
+		                        async: true,
+		                        success: function(json) {
+		                            var jsonObj;
+		                            jsonObj = json.listvmsnapshotresponse.vmSnapshot[0];
+		                            args.response.success({
+                                                actionFilter: vmSnapshotActionfilter,
+		                                data: jsonObj
+		                            });
+		                        }
+		                    });
+		                },
+		                tags: cloudStack.api.tags({
+		                    resourceType: 'VMSnapshot',
+		                    contextId: 'vmsnapshots'
+		                })
+		            }
+		        },
+		        actions: {
+		            //delete a snapshot
+		            remove: {
+		                label: 'label.action.vmsnapshot.delete',
+		                messages: {
+		                    confirm: function(args) {
+		                        return 'message.action.vmsnapshot.delete';
+		                    },
+		                    notification: function(args) {
+		                        return 'label.action.vmsnapshot.delete';
+		                    }
+		                },
+		                action: function(args) {
+		                    $.ajax({
+		                        url: createURL("deleteVMSnapshot&vmsnapshotid=" + args.context.vmsnapshots[0].id),
+		                        dataType: "json",
+		                        async: true,
+		                        success: function(json) {
+		                            var jid = json.deletevmsnapshotresponse.jobid;
+		                            args.response.success({
+		                                _custom: {
+		                                    jobId: jid
+		                                }
+		                            });
+		                        }
+		                    });
+		                },
+		                notification: {
+		                    poll: pollAsyncJobResult
+		                }
+		            },
+		            revertToVMSnapshot: {
+		                label: 'label.action.vmsnapshot.revert',
+		                messages: {
+		                    confirm: function(args) {
+		                        return 'label.action.vmsnapshot.revert';
+		                    },
+		                    notification: function(args) {
+		                        return 'message.action.vmsnapshot.revert';
+		                    }
+		                },
+		                action: function(args) {
+		                    $.ajax({
+		                        url: createURL("revertToVMSnapshot&vmsnapshotid=" + args.context.vmsnapshots[0].id),
+		                        dataType: "json",
+		                        async: true,
+		                        success: function(json) {
+		                            var jid = json.reverttovmsnapshotresponse.jobid;
+		                            args.response.success({
+		                                _custom: {
+		                                    jobId: jid
+		                                }
+		                            });
+		                        }
+		                    });
+
+		                },
+		                notification: {
+		                    poll: pollAsyncJobResult
+		                }
+		            },
+		            takeSnapshot: {
+		                label: 'Create Snapshot From VM Snapshot',
+		                messages: {
+		                    confirm: function(args) {
+		                        return 'Please confirm that you want to create a volume snapshot
from the vm snapshot.';
+		                    },
+		                    notification: function(args) {
+		                        return 'Volume snapshot is created from vm snapshot';
+		                    }
+		                },
+		                createForm: {
+		                    title: 'label.action.take.snapshot',
+		                    desc: 'message.action.take.snapshot',
+		                    fields: {
+		                        name: {
+		                            label: 'label.name',
+		                        },
+                                        volume: {
+                                            label: 'label.volume',
+                                            validation: {
+                                                required: true
+                                            },
+                                            select: function(args) {
+                                                $.ajax({
+                                                    url: createURL("listVolumes&virtualMachineId="
+ args.context.vmsnapshots[0].virtualmachineid),
+                                                    dataType: "json",
+                                                    async: true,
+                                                    success: function(json) {
+                                                        var volumes = json.listvolumesresponse.volume;
+                                                        var items = [];
+                                                        $(volumes).each(function() {
+                                                            items.push({
+                                                                id: this.id,
+                                                                description: this.name
+                                                            });
+                                                        });
+                                                        args.response.success({
+                                                            data: items
+                                                        });
+
+                                                    }
+                                                });
+                                            }
+                                        }
+		                    }
+		                },
+		                action: function(args) {
+		                    var data = {
+                                        volumeid: args.data.volume,
+		                        vmsnapshotid: args.context.vmsnapshots[0].id
+		                    };
+		                    if (args.data.name != null && args.data.name.length > 0)
{
+		                        $.extend(data, {
+		                            name: args.data.name
+		                        });
+		                    }
+		                    $.ajax({
+		                        url: createURL("createSnapshotFromVMSnapshot"),
+		                        data: data,
+		                        dataType: "json",
+		                        async: true,
+		                        success: function(json) {
+		                            var jid = json.createsnapshotfromvmsnapshotresponse.jobid;
+		                            args.response.success({
+		                                _custom: {
+		                                    jobId: jid
+		                                }
+		                            });
+		                        }
+		                    });
+
+		                },
+		                notification: {
+		                    poll: pollAsyncJobResult
+		                }
+		            }
+		        }
+		    }
+		    //detailview end
+		}
             }
         }
     };
@@ -2423,6 +2766,23 @@
         allowedActions.push("remove");
 
         return allowedActions;
+    };
+
+    var vmSnapshotActionfilter = cloudStack.actionFilter.vmSnapshotActionfilter = function(args)
{
+        var jsonObj = args.context.item;
+
+        if (jsonObj.state == 'Error') {
+            return ["remove"];
+        }
+
+        var allowedActions = [];
+        if (jsonObj.state == "Ready") {
+            allowedActions.push("remove");
+            allowedActions.push("revertToVMSnapshot");
+            allowedActions.push("takeSnapshot");
+        }
+
+        return allowedActions;
     }
 
 })(cloudStack);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a2428508/ui/scripts/vm_snapshots.js
----------------------------------------------------------------------
diff --git a/ui/scripts/vm_snapshots.js b/ui/scripts/vm_snapshots.js
deleted file mode 100644
index 98d7e37..0000000
--- a/ui/scripts/vm_snapshots.js
+++ /dev/null
@@ -1,198 +0,0 @@
-// 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.
-(function($, cloudStack) {
-    cloudStack.sections.vmsnapshots = {
-        title: 'label.vmsnapshot',
-        id: 'vmsnapshots',
-        listView: {
-            id: 'vmsnapshots',
-            isMaximized: true,
-            fields: {
-                displayname: {
-                    label: 'label.name'
-                },
-                state: {
-                    label: 'label.state',
-                    indicator: {
-                        'Ready': 'on',
-                        'Error': 'off'
-                    }
-                },
-                type: {
-                    label: 'label.vmsnapshot.type'
-                },
-                current: {
-                    label: 'label.vmsnapshot.current',
-                    converter: cloudStack.converters.toBooleanText
-                },
-                parentName: {
-                    label: 'label.vmsnapshot.parentname'
-                },
-                created: {
-                    label: 'label.date',
-                    converter: cloudStack.converters.toLocalDate
-                }
-            },
-
-            dataProvider: function(args) {
-                var apiCmd = "listVMSnapshot&listAll=true";
-                if (args.context != null) {
-                    if ("instances" in args.context) {
-                        apiCmd += "&virtualmachineid=" + args.context.instances[0].id;
-                    }
-                }
-                $.ajax({
-                    url: createURL(apiCmd),
-                    dataType: "json",
-                    async: true,
-                    success: function(json) {
-                        var jsonObj;
-                        jsonObj = json.listvmsnapshotresponse.vmSnapshot;
-                        args.response.success({
-                            data: jsonObj
-                        });
-                    }
-                });
-            },
-            //dataProvider end
-            detailView: {
-                tabs: {
-                    details: {
-                        title: 'label.details',
-                        fields: {
-                            id: {
-                                label: 'label.id'
-                            },
-                            name: {
-                                label: 'label.name'
-                            },
-                            displayname: {
-                                label: 'label.display.name'
-                            },
-                            type: {
-                                label: 'label.vmsnapshot.type'
-                            },
-                            description: {
-                                label: 'label.description'
-                            },
-                            state: {
-                                label: 'label.state',
-                                indicator: {
-                                    'Ready': 'on',
-                                    'Error': 'off'
-                                }
-                            },
-                            current: {
-                                label: 'label.vmsnapshot.current',
-                                converter: cloudStack.converters.toBooleanText
-                            },
-                            parentName: {
-                                label: 'label.vmsnapshot.parentname'
-                            },
-                            created: {
-                                label: 'label.date',
-                                converter: cloudStack.converters.toLocalDate
-                            }
-                        },
-                        dataProvider: function(args) {
-                            $.ajax({
-                                url: createURL("listVMSnapshot&listAll=true&vmsnapshotid="
+ args.context.vmsnapshots[0].id),
-                                dataType: "json",
-                                async: true,
-                                success: function(json) {
-                                    var jsonObj;
-                                    jsonObj = json.listvmsnapshotresponse.vmSnapshot[0];
-                                    args.response.success({
-                                        //actionFilter: vmActionfilter,
-                                        data: jsonObj
-                                    });
-                                }
-                            });
-                        },
-                        tags: cloudStack.api.tags({
-                            resourceType: 'VMSnapshot',
-                            contextId: 'vmsnapshots'
-                        })
-                    }
-                },
-                actions: {
-                    //delete a snapshot
-                    remove: {
-                        label: 'label.action.vmsnapshot.delete',
-                        messages: {
-                            confirm: function(args) {
-                                return 'message.action.vmsnapshot.delete';
-                            },
-                            notification: function(args) {
-                                return 'label.action.vmsnapshot.delete';
-                            }
-                        },
-                        action: function(args) {
-                            $.ajax({
-                                url: createURL("deleteVMSnapshot&vmsnapshotid=" + args.context.vmsnapshots[0].id),
-                                dataType: "json",
-                                async: true,
-                                success: function(json) {
-                                    var jid = json.deletevmsnapshotresponse.jobid;
-                                    args.response.success({
-                                        _custom: {
-                                            jobId: jid
-                                        }
-                                    });
-                                }
-                            });
-                        },
-                        notification: {
-                            poll: pollAsyncJobResult
-                        }
-                    },
-                    restart: {
-                        label: 'label.action.vmsnapshot.revert',
-                        messages: {
-                            confirm: function(args) {
-                                return 'label.action.vmsnapshot.revert';
-                            },
-                            notification: function(args) {
-                                return 'message.action.vmsnapshot.revert';
-                            }
-                        },
-                        action: function(args) {
-                            $.ajax({
-                                url: createURL("revertToVMSnapshot&vmsnapshotid=" + args.context.vmsnapshots[0].id),
-                                dataType: "json",
-                                async: true,
-                                success: function(json) {
-                                    var jid = json.reverttovmsnapshotresponse.jobid;
-                                    args.response.success({
-                                        _custom: {
-                                            jobId: jid
-                                        }
-                                    });
-                                }
-                            });
-
-                        },
-                        notification: {
-                            poll: pollAsyncJobResult
-                        }
-                    }
-                }
-            }
-            //detailview end
-        }
-    }
-})(jQuery, cloudStack);


Mime
View raw message