Shubhendu Tripathi has uploaded a new change for review.

Change subject: webadmin: UI for gluster volume snapshots
......................................................................

webadmin: UI for gluster volume snapshots

Introduced UI dialog for gluster volume snapshot creation and a subtab
to list the snapshots details.

Change-Id: I5161753920ef72c245f1785e754df97465a19602
Signed-off-by: Shubhendu Tripathi <[email protected]>
---
M 
backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/businessentities/gluster/GlusterVolumeSnapshotEntity.java
M 
frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/AppErrors.java
M 
frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/core/Common.gwt.xml
M 
frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/Linq.java
M 
frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/dataprovider/AsyncDataProvider.java
M 
frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/help/HelpTag.java
A 
frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/gluster/GlusterVolumeSnapshotListModel.java
A 
frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/gluster/GlusterVolumeSnapshotModel.java
M 
frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/volumes/VolumeListModel.java
M 
frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/place/WebAdminApplicationPlaces.java
M 
frontend/webadmin/modules/uicompat/src/main/java/org/ovirt/engine/ui/uicompat/LocalizedEnums.java
M 
frontend/webadmin/modules/uicompat/src/main/resources/org/ovirt/engine/ui/uicompat/LocalizedEnums.properties
M 
frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/ApplicationConstants.java
M 
frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/gin/ClientGinjectorExtension.java
M 
frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/gin/PresenterModule.java
M 
frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/gin/uicommon/VolumeModule.java
A 
frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/presenter/popup/gluster/GlusterVolumeSnapshotCreatePopupPresenterWidget.java
A 
frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/presenter/tab/gluster/SubTabGlusterVolumeSnapshotPresenter.java
A 
frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/popup/gluster/GlusterVolumeSnapshotCreatePopupView.java
A 
frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/popup/gluster/GlusterVolumeSnapshotCreatePopupView.ui.xml
M 
frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/tab/MainTabVolumeView.java
A 
frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/tab/gluster/SubTabGlusterVolumeSnapshotView.java
A 
frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/widget/table/column/GlusterVolumeSnapshotStatusCell.java
A 
frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/widget/table/column/GlusterVolumeSnapshotStatusColumn.java
24 files changed, 1,165 insertions(+), 186 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/34/36334/1

diff --git 
a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/businessentities/gluster/GlusterVolumeSnapshotEntity.java
 
b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/businessentities/gluster/GlusterVolumeSnapshotEntity.java
index edc3907..bde66d4 100644
--- 
a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/businessentities/gluster/GlusterVolumeSnapshotEntity.java
+++ 
b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/businessentities/gluster/GlusterVolumeSnapshotEntity.java
@@ -133,4 +133,9 @@
 
         return true;
     }
+
+    @Override
+    public Object getQueryableId() {
+        return this.snapshotId;
+    }
 }
diff --git 
a/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/AppErrors.java
 
b/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/AppErrors.java
index e568410..af5d542 100644
--- 
a/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/AppErrors.java
+++ 
b/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/AppErrors.java
@@ -2867,6 +2867,9 @@
     @DefaultStringValue("Cannot ${action} ${type}. Gluster Volume is down.")
     String ACTION_TYPE_FAILED_GLUSTER_VOLUME_IS_DOWN();
 
+    @DefaultStringValue("Cannot ${action} ${type}. Gluster volume is not 
thinly provisioned")
+    String ACTION_TYPE_FAILED_GLUSTER_VOLUME_IS_NOT_THINLY_PROVISIONED();
+
     @DefaultStringValue("Cannot ${action} ${type}. Cannot remove all the 
bricks from a Volume.")
     String ACTION_TYPE_FAILED_CAN_NOT_REMOVE_ALL_BRICKS_FROM_VOLUME();
 
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/core/Common.gwt.xml
 
b/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/core/Common.gwt.xml
index 11bccb2..7f5cf11 100644
--- 
a/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/core/Common.gwt.xml
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/core/Common.gwt.xml
@@ -355,6 +355,8 @@
         <include 
name="common/businessentities/gluster/GlusterGeoRepSession.java"/>
         <include 
name="common/businessentities/gluster/GlusterGeoRepSessionDetails.java"/>
         <include 
name="common/businessentities/gluster/GlusterGeoRepSessionConfiguration.java"/>
+        <include 
name="common/businessentities/gluster/GlusterVolumeSnapshotEntity.java"/>
+        <include 
name="common/businessentities/gluster/GlusterSnapshotStatus.java"/>
                <!-- Scheduling -->
                <include name="common/scheduling/*.java"/>
                <include name="common/scheduling/parameters/*.java"/>
diff --git 
a/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/Linq.java
 
b/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/Linq.java
index 07cf87f..e9e7f1a 100644
--- 
a/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/Linq.java
+++ 
b/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/Linq.java
@@ -41,6 +41,7 @@
 import 
org.ovirt.engine.core.common.businessentities.gluster.GlusterBrickEntity;
 import 
org.ovirt.engine.core.common.businessentities.gluster.GlusterGeoRepSession;
 import org.ovirt.engine.core.common.businessentities.network.HostNetworkQos;
+import 
org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeSnapshotEntity;
 import org.ovirt.engine.core.common.businessentities.network.Network;
 import org.ovirt.engine.core.common.businessentities.network.NetworkInterface;
 import org.ovirt.engine.core.common.businessentities.network.NetworkQoS;
@@ -139,6 +140,15 @@
         }
     }
 
+    public static class GlusterVolumeSnapshotComparer implements 
Comparator<GlusterVolumeSnapshotEntity>, Serializable {
+        private static final long serialVersionUID = -6085272225112945249L;
+
+        @Override
+        public int compare(GlusterVolumeSnapshotEntity snapshot0, 
GlusterVolumeSnapshotEntity snapshot1) {
+            return 
snapshot0.getSnapshotName().compareTo(snapshot1.getSnapshotName());
+        }
+    }
+
     public static class DiskImageByLastModifiedComparer implements 
Comparator<DiskImage>, Serializable
     {
 
diff --git 
a/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/dataprovider/AsyncDataProvider.java
 
b/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/dataprovider/AsyncDataProvider.java
index b11a5a4..451db51 100644
--- 
a/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/dataprovider/AsyncDataProvider.java
+++ 
b/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/dataprovider/AsyncDataProvider.java
@@ -77,6 +77,7 @@
 import org.ovirt.engine.core.common.businessentities.gluster.GlusterHookEntity;
 import 
org.ovirt.engine.core.common.businessentities.gluster.GlusterServerService;
 import 
org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeEntity;
+import 
org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeSnapshotEntity;
 import org.ovirt.engine.core.common.businessentities.gluster.ServiceType;
 import org.ovirt.engine.core.common.businessentities.network.HostNetworkQos;
 import org.ovirt.engine.core.common.businessentities.network.Network;
@@ -1580,6 +1581,16 @@
         
Frontend.getInstance().runQuery(VdcQueryType.GetGlusterVolumeGeoRepSessions, 
new IdQueryParameters(masterVolumeId), aQuery);
     }
 
+    public void getGlusterVolumeSnapshotsForVolume(AsyncQuery aQuery, Guid 
volumeId) {
+        aQuery.converterCallback = new IAsyncConverter() {
+            @Override
+            public Object Convert(Object source, AsyncQuery asyncQuery) {
+                return source != null ? source : new 
ArrayList<GlusterVolumeSnapshotEntity>();
+            }
+        };
+        
Frontend.getInstance().runQuery(VdcQueryType.GetGlusterVolumeSnapshotsByVolumeId,
 new IdQueryParameters(volumeId), aQuery);
+    }
+
     public void getGlusterHook(AsyncQuery aQuery, Guid hookId, boolean 
includeServerHooks) {
         aQuery.converterCallback = new IAsyncConverter() {
             @Override
diff --git 
a/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/help/HelpTag.java
 
b/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/help/HelpTag.java
index 55ec0a6..30a9ae2 100644
--- 
a/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/help/HelpTag.java
+++ 
b/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/help/HelpTag.java
@@ -332,6 +332,8 @@
 
     new_volume("new_volume", HelpTagType.WEBADMIN, "[gluster] Volumes main tab 
-> New"), //$NON-NLS-1$ //$NON-NLS-2$
 
+    new_volume_snapshot("new_volume_snapshot", HelpTagType.WEBADMIN, 
"[gluster] Volumes main tab -> Snapshot -> New"), //$NON-NLS-1$ //$NON-NLS-2$
+
     parameters("parameters", HelpTagType.UNKNOWN), //$NON-NLS-1$
 
     permissions("permissions", HelpTagType.UNKNOWN), //$NON-NLS-1$
@@ -482,6 +484,8 @@
 
     volume_stop("volume_stop", HelpTagType.WEBADMIN, "Volumes Tab > Stop 
Volume"), //$NON-NLS-1$ //$NON-NLS-2$
 
+    volume_snapshots("volume_snapshots", HelpTagType.WEBADMIN), //$NON-NLS-1$
+
     new_role("new_role", HelpTagType.WEBADMIN), //$NON-NLS-1$
 
     edit_role("edit_role", HelpTagType.WEBADMIN), //$NON-NLS-1$
diff --git 
a/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/gluster/GlusterVolumeSnapshotListModel.java
 
b/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/gluster/GlusterVolumeSnapshotListModel.java
new file mode 100644
index 0000000..8815df0
--- /dev/null
+++ 
b/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/gluster/GlusterVolumeSnapshotListModel.java
@@ -0,0 +1,187 @@
+package org.ovirt.engine.ui.uicommonweb.models.gluster;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.ovirt.engine.core.common.action.VdcActionType;
+import org.ovirt.engine.core.common.action.VdcReturnValueBase;
+import 
org.ovirt.engine.core.common.action.gluster.CreateGlusterVolumeSnapshotParameters;
+import org.ovirt.engine.core.common.businessentities.gluster.GlusterStatus;
+import 
org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeEntity;
+import 
org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeSnapshotEntity;
+import org.ovirt.engine.ui.frontend.AsyncQuery;
+import org.ovirt.engine.ui.frontend.Frontend;
+import org.ovirt.engine.ui.frontend.INewAsyncCallback;
+import org.ovirt.engine.ui.uicommonweb.Linq;
+import org.ovirt.engine.ui.uicommonweb.UICommand;
+import org.ovirt.engine.ui.uicommonweb.dataprovider.AsyncDataProvider;
+import org.ovirt.engine.ui.uicommonweb.help.HelpTag;
+import org.ovirt.engine.ui.uicommonweb.models.SearchableListModel;
+import org.ovirt.engine.ui.uicompat.ConstantsManager;
+import org.ovirt.engine.ui.uicompat.FrontendActionAsyncResult;
+import org.ovirt.engine.ui.uicompat.IFrontendActionAsyncCallback;
+import org.ovirt.engine.ui.uicompat.UIConstants;
+
+public class GlusterVolumeSnapshotListModel extends SearchableListModel {
+
+    private UICommand newSnapshotCommand;
+
+    public UICommand getNewSnapshotCommand() {
+        return newSnapshotCommand;
+    }
+
+    public void setNewSnapshotCommand(UICommand value) {
+        this.newSnapshotCommand = value;
+    }
+
+    @Override
+    public String getListName() {
+        return "GlusterVolumeSnapshotModel"; //$NON-NLS-1$
+    }
+
+    public GlusterVolumeSnapshotListModel() {
+        
setTitle(ConstantsManager.getInstance().getConstants().snapshotsTitle());
+        setHelpTag(HelpTag.volume_snapshots);
+        setHashName("volume_snapshots");//$NON-NLS-1$
+        setNewSnapshotCommand(new UICommand("createSnapshot", 
this));//$NON-NLS-1$
+    }
+
+    @Override
+    protected void onEntityChanged() {
+        super.onEntityChanged();
+        getSearchCommand().execute();
+    }
+
+    @Override
+    protected void onSelectedItemChanged() {
+        super.onSelectedItemChanged();
+        updateActionAvailability();
+    }
+
+    @Override
+    protected void selectedItemsChanged()
+    {
+        super.selectedItemsChanged();
+        updateActionAvailability();
+    }
+
+    @Override
+    protected void syncSearch() {
+        if (getEntity() == null) {
+            return;
+        }
+
+        AsyncDataProvider.getInstance().getGlusterVolumeSnapshotsForVolume(new 
AsyncQuery(this,
+                new INewAsyncCallback() {
+
+                    @Override
+                    public void onSuccess(Object model, Object returnValue) {
+                        List<GlusterVolumeSnapshotEntity> snapshots =
+                                (ArrayList<GlusterVolumeSnapshotEntity>) 
returnValue;
+                        Collections.sort(snapshots, new 
Linq.GlusterVolumeSnapshotComparer());
+                        setItems(snapshots);
+                    }
+                }), getEntity().getId());
+    }
+
+    private void updateActionAvailability() {
+        boolean allowCreateSnapshot = true;
+
+        if (getEntity() == null || getEntity().getStatus() == 
GlusterStatus.DOWN) {
+            allowCreateSnapshot = false;
+        }
+
+        getNewSnapshotCommand().setIsAvailable(allowCreateSnapshot);
+    }
+
+    @Override
+    public void executeCommand(UICommand command) {
+        super.executeCommand(command);
+
+        if (command.equals(getNewSnapshotCommand())) {
+            newSnapshot();
+        } else if (command.getName().equalsIgnoreCase("onCreateSnapshot")) 
{//$NON-NLS-1$
+            onCreateSnapshot();
+        } else if (command.getName().equalsIgnoreCase("Cancel")) {//$NON-NLS-1$
+            setWindow(null);
+        }
+    }
+
+    @Override
+    public GlusterVolumeEntity getEntity() {
+        return (GlusterVolumeEntity) super.getEntity();
+    }
+
+    public void setEntity(GlusterVolumeEntity value) {
+        super.setEntity(value);
+    }
+
+    private void newSnapshot() {
+        if (getWindow() != null) {
+            return;
+        }
+
+        final UIConstants constants = 
ConstantsManager.getInstance().getConstants();
+
+        GlusterVolumeEntity volumeEntity = getEntity();
+        GlusterVolumeSnapshotModel snapshotModel = new 
GlusterVolumeSnapshotModel();
+        snapshotModel.setHelpTag(HelpTag.new_volume_snapshot);
+        snapshotModel.setHashName("new_volume_snapshot"); //$NON-NLS-1$
+        
snapshotModel.setTitle(ConstantsManager.getInstance().getConstants().createSnapshotTitle());
+        setWindow(snapshotModel);
+
+        
snapshotModel.getClusterName().setEntity(volumeEntity.getVdsGroupName());
+        snapshotModel.getVolumeName().setEntity(volumeEntity.getName());
+
+        UICommand okCommand = new UICommand("onCreateSnapshot", this); 
//$NON-NLS-1$
+        okCommand.setTitle(constants.ok());
+        okCommand.setIsDefault(true);
+        snapshotModel.getCommands().add(okCommand);
+
+        UICommand cancelCommand = new UICommand("Cancel", this); //$NON-NLS-1$
+        cancelCommand.setTitle(constants.cancel());
+        cancelCommand.setIsCancel(true);
+        snapshotModel.getCommands().add(cancelCommand);
+    }
+
+    private void onCreateSnapshot() {
+        GlusterVolumeSnapshotModel snapshotModel = 
(GlusterVolumeSnapshotModel) getWindow();
+
+        if (!snapshotModel.validate()) {
+            return;
+        }
+
+        final GlusterVolumeSnapshotEntity snapshot = new 
GlusterVolumeSnapshotEntity();
+        GlusterVolumeEntity volumeEntity = (GlusterVolumeEntity) getEntity();
+        snapshot.setClusterId(volumeEntity.getClusterId());
+        snapshot.setSnapshotName(snapshotModel.getSnapshotName().getEntity());
+        snapshot.setVolumeId(volumeEntity.getId());
+        snapshot.setDescription(snapshotModel.getDescription().getEntity());
+        boolean force = snapshotModel.getForceCreate().getEntity();
+
+        CreateGlusterVolumeSnapshotParameters parameter =
+                new CreateGlusterVolumeSnapshotParameters(snapshot, force);
+
+        snapshotModel.startProgress(null);
+        
Frontend.getInstance().runAction(VdcActionType.CreateGlusterVolumeSnapshot,
+                parameter,
+                new IFrontendActionAsyncCallback() {
+                    @Override
+                    public void executed(FrontendActionAsyncResult result) {
+                        GlusterVolumeSnapshotListModel localModel = 
(GlusterVolumeSnapshotListModel) result.getState();
+                        localModel.stopProgress();
+                        
localModel.postOnCreateSnapshot(result.getReturnValue(), snapshot);
+                    }
+                },
+                this);
+    }
+
+    public void postOnCreateSnapshot(VdcReturnValueBase returnValue, 
GlusterVolumeSnapshotEntity snapshot) {
+        GlusterVolumeSnapshotModel model = (GlusterVolumeSnapshotModel) 
getWindow();
+
+        if (returnValue != null && returnValue.getSucceeded()) {
+            setWindow(null);
+        }
+    }
+}
diff --git 
a/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/gluster/GlusterVolumeSnapshotModel.java
 
b/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/gluster/GlusterVolumeSnapshotModel.java
new file mode 100644
index 0000000..0f9e70c
--- /dev/null
+++ 
b/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/gluster/GlusterVolumeSnapshotModel.java
@@ -0,0 +1,117 @@
+package org.ovirt.engine.ui.uicommonweb.models.gluster;
+
+import org.ovirt.engine.ui.uicommonweb.models.EntityModel;
+import org.ovirt.engine.ui.uicommonweb.models.Model;
+import org.ovirt.engine.ui.uicommonweb.validation.AsciiNameValidation;
+import org.ovirt.engine.ui.uicommonweb.validation.IValidation;
+import org.ovirt.engine.ui.uicommonweb.validation.LengthValidation;
+import org.ovirt.engine.ui.uicommonweb.validation.NotEmptyValidation;
+
+public class GlusterVolumeSnapshotModel extends Model {
+    private EntityModel<String> dataCenter;
+    private EntityModel<String> clusterName;
+    private EntityModel<String> volumeName;
+    private EntityModel<String> snapshotName;
+    private EntityModel<String> description;
+    private EntityModel<Boolean> forceCreate;
+    private EntityModel<Boolean> activate;
+    private String volumeQuotaMessage = "";
+
+    public GlusterVolumeSnapshotModel() {
+        init();
+        setAvailabilities();
+    }
+
+    private void init() {
+        setDataCenter(new EntityModel<String>());
+        setClusterName(new EntityModel<String>());
+        setVolumeName(new EntityModel<String>());
+        setSnapshotName(new EntityModel<String>());
+        setDescription(new EntityModel<String>());
+        setForceCreate(new EntityModel<Boolean>());
+        setActivate(new EntityModel<Boolean>());
+
+        getForceCreate().setEntity(false);
+        getActivate().setEntity(true);
+    }
+
+    private void setAvailabilities() {
+        getClusterName().setIsAvailable(true);
+        getVolumeName().setIsAvailable(true);
+        getSnapshotName().setIsAvailable(true);
+        getDescription().setIsAvailable(true);
+        getForceCreate().setIsAvailable(true);
+        getActivate().setIsAvailable(true);
+    }
+
+    public EntityModel<String> getDataCenter() {
+        return this.dataCenter;
+    }
+
+    public void setDataCenter(EntityModel<String> dataCenter) {
+        this.dataCenter = dataCenter;
+    }
+
+    public EntityModel<String> getClusterName() {
+        return clusterName;
+    }
+
+    public void setClusterName(EntityModel<String> clusterName) {
+        this.clusterName = clusterName;
+    }
+
+    public EntityModel<String> getVolumeName() {
+        return volumeName;
+    }
+
+    public void setVolumeName(EntityModel<String> volumeName) {
+        this.volumeName = volumeName;
+    }
+
+    public EntityModel<String> getSnapshotName() {
+        return snapshotName;
+    }
+
+    public void setSnapshotName(EntityModel<String> snapshotName) {
+        this.snapshotName = snapshotName;
+    }
+
+    public EntityModel<String> getDescription() {
+        return description;
+    }
+
+    public void setDescription(EntityModel<String> description) {
+        this.description = description;
+    }
+
+    public EntityModel<Boolean> getForceCreate() {
+        return forceCreate;
+    }
+
+    public void setForceCreate(EntityModel<Boolean> forceCreate) {
+        this.forceCreate = forceCreate;
+    }
+
+    public EntityModel<Boolean> getActivate() {
+        return activate;
+    }
+
+    public void setActivate(EntityModel<Boolean> activate) {
+        this.activate = activate;
+    }
+
+    public String getVolumeQuotaMessage() {
+        return this.volumeQuotaMessage;
+    }
+
+    public void setVolumeQuotaMessage(String value) {
+        this.volumeQuotaMessage = value;
+    }
+
+    public boolean validate() {
+        getSnapshotName().validateEntity(new IValidation[] { new 
NotEmptyValidation(), new LengthValidation(50),
+                new AsciiNameValidation() });
+
+        return getSnapshotName().getIsValid();
+    }
+}
diff --git 
a/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/volumes/VolumeListModel.java
 
b/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/volumes/VolumeListModel.java
index db5b5cb..cf39e52 100644
--- 
a/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/volumes/VolumeListModel.java
+++ 
b/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/volumes/VolumeListModel.java
@@ -60,6 +60,7 @@
 import 
org.ovirt.engine.ui.uicommonweb.models.gluster.VolumeProfileStatisticsModel;
 import 
org.ovirt.engine.ui.uicommonweb.models.gluster.VolumeRebalanceStatusModel;
 import org.ovirt.engine.ui.uicommonweb.place.WebAdminApplicationPlaces;
+import 
org.ovirt.engine.ui.uicommonweb.models.gluster.GlusterVolumeSnapshotListModel;
 import org.ovirt.engine.ui.uicompat.ConstantsManager;
 import org.ovirt.engine.ui.uicompat.FrontendActionAsyncResult;
 import org.ovirt.engine.ui.uicompat.FrontendMultipleActionAsyncResult;
@@ -106,6 +107,7 @@
     private UICommand startVolumeProfilingCommand;
     private UICommand showVolumeProfileDetailsCommand;
     private UICommand stopVolumeProfilingCommand;
+    private UICommand createSnapshotCommand;
 
     public UICommand getStartRebalanceCommand() {
         return startRebalanceCommand;
@@ -122,6 +124,7 @@
     public void setStopRebalanceCommand(UICommand stopRebalanceCommand) {
         this.stopRebalanceCommand = stopRebalanceCommand;
     }
+
     private UICommand statusRebalanceCommand;
 
     public UICommand getStatusRebalanceCommand() {
@@ -168,6 +171,12 @@
         return geoRepListModel;
     }
 
+    private final GlusterVolumeSnapshotListModel snapshotListModel;
+
+    public GlusterVolumeSnapshotListModel getSnapshotListModel() {
+        return snapshotListModel;
+    }
+
     public UICommand getStartVolumeProfilingCommand() {
         return startVolumeProfilingCommand;
     }
@@ -192,20 +201,33 @@
         this.stopVolumeProfilingCommand = stopVolumeProfilingCommand;
     }
 
+    public UICommand getCreateSnapshotCommand() {
+        return this.createSnapshotCommand;
+    }
+
+    public void setCreateSnapshotCommand(UICommand command) {
+        this.createSnapshotCommand = command;
+    }
+
     @Inject
-    public VolumeListModel(final VolumeBrickListModel volumeBrickListModel, 
final VolumeGeneralModel volumeGeneralModel,
+    public VolumeListModel(final VolumeBrickListModel volumeBrickListModel,
+            final VolumeGeneralModel volumeGeneralModel,
             final VolumeParameterListModel volumeParameterListModel,
-            final PermissionListModel<VolumeListModel> permissionListModel,
-            final VolumeEventListModel volumeEventListModel, final 
VolumeGeoRepListModel geoRepListModel) {
+            final PermissionListModel permissionListModel,
+            final VolumeEventListModel volumeEventListModel,
+            final VolumeGeoRepListModel geoRepListModel,
+            final GlusterVolumeSnapshotListModel snapshotListModel) {
         this.brickListModel = volumeBrickListModel;
         this.geoRepListModel = geoRepListModel;
+        this.snapshotListModel = snapshotListModel;
         setDetailList(volumeGeneralModel, volumeParameterListModel, 
permissionListModel, volumeEventListModel);
         setTitle(ConstantsManager.getInstance().getConstants().volumesTitle());
         setApplicationPlace(WebAdminApplicationPlaces.volumeMainTabPlace);
 
         setDefaultSearchString("Volumes:"); //$NON-NLS-1$
         setSearchString(getDefaultSearchString());
-        setSearchObjects(new String[] { SearchObjects.GLUSTER_VOLUME_OBJ_NAME, 
SearchObjects.GLUSTER_VOLUME_PLU_OBJ_NAME });
+        setSearchObjects(new String[] { SearchObjects.GLUSTER_VOLUME_OBJ_NAME,
+                SearchObjects.GLUSTER_VOLUME_PLU_OBJ_NAME });
         setAvailableInModes(ApplicationMode.GlusterOnly);
 
         setNewVolumeCommand(new UICommand("Create Volume", this)); 
//$NON-NLS-1$
@@ -219,6 +241,7 @@
         setShowVolumeProfileDetailsCommand(new UICommand("showProfileDetails", 
this));//$NON-NLS-1$
         setStopVolumeProfilingCommand(new UICommand("stopProfiling", 
this));//$NON-NLS-1$
         setOptimizeForVirtStoreCommand(new UICommand("OptimizeForVirtStore", 
this)); //$NON-NLS-1$
+        setCreateSnapshotCommand(new UICommand("createSnapshot", this)); 
//$NON-NLS-1$
 
         getRemoveVolumeCommand().setIsExecutionAllowed(false);
         getStartCommand().setIsExecutionAllowed(false);
@@ -245,6 +268,7 @@
         list.add(getGeoRepListModel());
         list.add(permissionListModel);
         list.add(volumeEventListModel);
+        list.add(getSnapshotListModel());
         setDetailModels(list);
     }
 
@@ -282,7 +306,7 @@
                             if (dc.getId().equals(cluster.getStoragePoolId()))
                             {
                                 innerVolumeModel.getDataCenter()
-                                        .setItems(new 
ArrayList<StoragePool>(Arrays.asList(new StoragePool[] {dc})));
+                                        .setItems(new 
ArrayList<StoragePool>(Arrays.asList(new StoragePool[] { dc })));
                                 
innerVolumeModel.getDataCenter().setSelectedItem(dc);
                                 break;
                             }
@@ -323,7 +347,7 @@
                 
command.setTitle(ConstantsManager.getInstance().getConstants().ok());
                 command.setIsDefault(true);
                 innerVolumeModel.getCommands().add(command);
-                command = new UICommand("Cancel", volumeListModel);  
//$NON-NLS-1$
+                command = new UICommand("Cancel", volumeListModel); 
//$NON-NLS-1$
                 
command.setTitle(ConstantsManager.getInstance().getConstants().cancel());
                 command.setIsCancel(true);
                 innerVolumeModel.getCommands().add(command);
@@ -408,7 +432,8 @@
 
     @Override
     protected void syncSearch() {
-        SearchParameters tempVar = new SearchParameters(getSearchString(), 
SearchType.GlusterVolume, isCaseSensitiveSearch());
+        SearchParameters tempVar =
+                new SearchParameters(getSearchString(), 
SearchType.GlusterVolume, isCaseSensitiveSearch());
         tempVar.setMaxCount(getSearchPageSize());
         super.syncSearch(VdcQueryType.Search, tempVar);
     }
@@ -417,9 +442,10 @@
     protected void onSelectedItemChanged() {
         super.onSelectedItemChanged();
         updateActionAvailability();
-        GlusterVolumeEntity selectedVolume = 
(GlusterVolumeEntity)provideDetailModelEntity(getSelectedItem());
+        GlusterVolumeEntity selectedVolume = (GlusterVolumeEntity) 
provideDetailModelEntity(getSelectedItem());
         getBrickListModel().setVolumeEntity(selectedVolume);
         getGeoRepListModel().setEntity(selectedVolume);
+        getSnapshotListModel().setEntity(selectedVolume);
     }
 
     @Override
@@ -440,6 +466,7 @@
         boolean allowStartProfiling = false;
         boolean allowStopProfiling = false;
         boolean allowProfileStatisticsDetails = false;
+        boolean allowCreateSnapshot = false;
 
         if (getSelectedItems() == null || getSelectedItems().size() == 0) {
             allowStart = false;
@@ -486,6 +513,7 @@
             }
             allowStatusRebalance = 
getRebalanceStatusAvailability(getSelectedItems());
             allowProfileStatisticsDetails = 
getProfileStatisticsAvailability(list);
+            allowCreateSnapshot = isCreateSnapshotAvailable(list);
         }
         getStartCommand().setIsExecutionAllowed(allowStart);
         getStopCommand().setIsExecutionAllowed(allowStop);
@@ -494,6 +522,7 @@
         getStopRebalanceCommand().setIsExecutionAllowed(allowStopRebalance);
         
getStatusRebalanceCommand().setIsExecutionAllowed(allowStatusRebalance);
         getOptimizeForVirtStoreCommand().setIsExecutionAllowed(allowOptimize);
+        getCreateSnapshotCommand().setIsExecutionAllowed(allowCreateSnapshot);
 
         // System tree dependent actions.
         boolean isAvailable =
@@ -506,6 +535,15 @@
         
getShowVolumeProfileDetailsCommand().setIsExecutionAllowed(allowProfileStatisticsDetails);
     }
 
+    private boolean isCreateSnapshotAvailable(List<GlusterVolumeEntity> list) {
+        if (getSelectedItems().size() == 1) {
+            GlusterVolumeEntity volumeEntity = list.get(0);
+            return (volumeEntity.getStatus() == GlusterStatus.UP);
+        } else {
+            return false;
+        }
+    }
+
     private boolean isStopProfileAvailable(List<GlusterVolumeEntity> list) {
         if (getSelectedItems().size() == 0) {
             return false;
@@ -514,7 +552,7 @@
                 if (volumeEntity.getStatus() == GlusterStatus.DOWN) {
                     return false;
                 }
-                if 
((volumeEntity.getOptionValue("diagnostics.latency-measurement") == null)|| 
(!(volumeEntity.getOptionValue("diagnostics.latency-measurement").equals("on"))))
 {//$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
+                if 
((volumeEntity.getOptionValue("diagnostics.latency-measurement") == null) || 
(!(volumeEntity.getOptionValue("diagnostics.latency-measurement").equals("on"))))
 {//$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
                     return false;
                 }
             }
@@ -550,9 +588,9 @@
     }
 
     private boolean getProfileStatisticsAvailability(List<GlusterVolumeEntity> 
selectedVolumes) {
-        if(selectedVolumes.size() == 1) {
+        if (selectedVolumes.size() == 1) {
             GlusterVolumeEntity selectedVolume = selectedVolumes.get(0);
-            if(selectedVolume.getStatus() == GlusterStatus.UP) {
+            if (selectedVolume.getStatus() == GlusterStatus.UP) {
                 return true;
             }
         }
@@ -571,7 +609,7 @@
         }
         else if (command.equals(getRemoveVolumeCommand())) {
             removeVolume();
-        } else if(command.getName().equals("rebalanceNotStarted")) 
{//$NON-NLS-1$
+        } else if (command.getName().equals("rebalanceNotStarted")) 
{//$NON-NLS-1$
             closeConfirmationWindow();
         }
         else if (command.getName().equals("Cancel")) { //$NON-NLS-1$
@@ -594,30 +632,33 @@
             setConfirmWindow(null);
         } else if (command.getName().equals("CancelRebalanceStatus")) 
{//$NON-NLS-1$
             cancelRebalanceStatus();
-        }else if (command.equals(getOptimizeForVirtStoreCommand())) {
+        } else if (command.equals(getOptimizeForVirtStoreCommand())) {
             optimizeForVirtStore();
         } else if (command.getName().equals("onStop")) {//$NON-NLS-1$
             onStop();
         } else if (command.getName().equals("OnRemove")) { //$NON-NLS-1$
             onRemoveVolume();
-        } else if(command.getName().equals("stop_rebalance_from_status")) 
{//$NON-NLS-1$
+        } else if (command.getName().equals("stop_rebalance_from_status")) 
{//$NON-NLS-1$
             stopRebalance();
-        } else if(command.equals(getStartVolumeProfilingCommand()) || 
command.getName().equals("startProfiling")) {//$NON-NLS-1$
+        } else if (command.equals(getStartVolumeProfilingCommand()) || 
command.getName().equals("startProfiling")) {//$NON-NLS-1$
             startVolumeProfiling();
-        } else if(command.equals(getStopVolumeProfilingCommand()) || 
command.getName().equals("stopProfiling")) {//$NON-NLS-1$
+        } else if (command.equals(getStopVolumeProfilingCommand()) || 
command.getName().equals("stopProfiling")) {//$NON-NLS-1$
             stopVolumeProfiling();
-        } else if(command.equals(getShowVolumeProfileDetailsCommand()) || 
command.getName().equals("showProfileDetails")) {//$NON-NLS-1$
+        } else if (command.equals(getShowVolumeProfileDetailsCommand())
+                || command.getName().equals("showProfileDetails")) 
{//$NON-NLS-1$
             showVolumeProfiling();
-        }else if(command.getName().equalsIgnoreCase("closeProfileStats")) 
{//$NON-NLS-1$
+        } else if (command.getName().equalsIgnoreCase("closeProfileStats")) 
{//$NON-NLS-1$
             setWindow(null);
-        } else 
if(command.getName().equalsIgnoreCase("CancelOptimizeForVirtStore")) 
{//$NON-NLS-1$
+        } else if 
(command.getName().equalsIgnoreCase("CancelOptimizeForVirtStore")) 
{//$NON-NLS-1$
             setConfirmWindow(null);
         } else if 
(command.getName().equalsIgnoreCase("ConfirmOptimiseForVirtStore")) 
{//$NON-NLS-1$
             List<GlusterVolumeEntity> selectedVolumes = new 
ArrayList<GlusterVolumeEntity>();
-            for(Object selectedVolume : getSelectedItems()) {
+            for (Object selectedVolume : getSelectedItems()) {
                 selectedVolumes.add((GlusterVolumeEntity) selectedVolume);
             }
             optimizeVolumesForVirtStore(selectedVolumes);
+        } else if (command.equals(getCreateSnapshotCommand())) {
+            getSnapshotListModel().getNewSnapshotCommand().execute();
         }
     }
 
@@ -648,7 +689,7 @@
     }
 
     private void closeConfirmationWindow() {
-        if(getConfirmWindow() == null) {
+        if (getConfirmWindow() == null) {
             return;
         }
         getConfirmWindow().stopProgress();
@@ -707,20 +748,23 @@
         model.startProgress(null);
 
         final GlusterVolumeEntity volumeEntity = (GlusterVolumeEntity) 
getSelectedItem();
-        GlusterVolumeRebalanceParameters param = new 
GlusterVolumeRebalanceParameters(volumeEntity.getId(), false, false);
+        GlusterVolumeRebalanceParameters param =
+                new GlusterVolumeRebalanceParameters(volumeEntity.getId(), 
false, false);
 
-        
Frontend.getInstance().runAction(VdcActionType.StopRebalanceGlusterVolume, 
param, new IFrontendActionAsyncCallback() {
+        
Frontend.getInstance().runAction(VdcActionType.StopRebalanceGlusterVolume,
+                param,
+                new IFrontendActionAsyncCallback() {
 
-            @Override
-            public void executed(FrontendActionAsyncResult result) {
-                ConfirmationModel localModel = (ConfirmationModel) 
getConfirmWindow();
-                localModel.stopProgress();
-                setConfirmWindow(null);
-                if (result.getReturnValue().getSucceeded()) {
-                    showRebalanceStatus();
-                }
-            }
-        });
+                    @Override
+                    public void executed(FrontendActionAsyncResult result) {
+                        ConfirmationModel localModel = (ConfirmationModel) 
getConfirmWindow();
+                        localModel.stopProgress();
+                        setConfirmWindow(null);
+                        if (result.getReturnValue().getSucceeded()) {
+                            showRebalanceStatus();
+                        }
+                    }
+                });
     }
 
     private void showRebalanceStatus() {
@@ -745,9 +789,11 @@
             public void onSuccess(Object model, Object returnValue) {
                 cModel.stopProgress();
                 VdcQueryReturnValue vdcValue = (VdcQueryReturnValue) 
returnValue;
-                GlusterVolumeTaskStatusEntity rebalanceStatusEntity 
=vdcValue.getReturnValue();
+                GlusterVolumeTaskStatusEntity rebalanceStatusEntity = 
vdcValue.getReturnValue();
                 if ((rebalanceStatusEntity == null) || 
!(vdcValue.getSucceeded())) {
-                    
cModel.setMessage(ConstantsManager.getInstance().getMessages().rebalanceStatusFailed(volumeEntity.getName()));
+                    cModel.setMessage(ConstantsManager.getInstance()
+                            .getMessages()
+                            .rebalanceStatusFailed(volumeEntity.getName()));
                 } else {
                     setConfirmWindow(null);
                     if (getWindow() == null) {
@@ -762,7 +808,8 @@
                         
rebalanceStatusModel.getVolume().setEntity(volumeEntity.getName());
                         
rebalanceStatusModel.getCluster().setEntity(volumeEntity.getVdsGroupName());
 
-                        UICommand stopRebalanceFromStatus = new 
UICommand("stop_rebalance_from_status", VolumeListModel.this);//$NON-NLS-1$
+                        UICommand stopRebalanceFromStatus =
+                                new UICommand("stop_rebalance_from_status", 
VolumeListModel.this);//$NON-NLS-1$
                         
stopRebalanceFromStatus.setTitle(ConstantsManager.getInstance().getConstants().stopRebalance());
                         
rebalanceStatusModel.getCommands().add(stopRebalanceFromStatus);
                         
rebalanceStatusModel.setStopReblanceFromStatus(stopRebalanceFromStatus);
@@ -773,7 +820,7 @@
                         
rebalanceStatusModel.getCommands().add(cancelRebalance);
 
                         rebalanceStatusModel.showStatus(rebalanceStatusEntity);
-                    }else {
+                    } else {
                         VolumeRebalanceStatusModel statusModel = 
(VolumeRebalanceStatusModel) getWindow();
                         
statusModel.getCommands().get(0).setIsExecutionAllowed(false);
                         statusModel.showStatus(rebalanceStatusEntity);
@@ -787,11 +834,14 @@
     }
 
     private void showVolumeProfiling() {
-        if(getSelectedItem() == null || getWindow()!= null) {
+        if (getSelectedItem() == null || getWindow() != null) {
             return;
         }
-        GlusterVolumeEntity selectedVolume = 
(GlusterVolumeEntity)getSelectedItem();
-        VolumeProfileStatisticsModel profileStatsModel = new 
VolumeProfileStatisticsModel(selectedVolume.getClusterId(), 
selectedVolume.getId(), selectedVolume.getName());
+        GlusterVolumeEntity selectedVolume = (GlusterVolumeEntity) 
getSelectedItem();
+        VolumeProfileStatisticsModel profileStatsModel =
+                new VolumeProfileStatisticsModel(selectedVolume.getClusterId(),
+                        selectedVolume.getId(),
+                        selectedVolume.getName());
 
         setWindow(profileStatsModel);
         setHelpTag(HelpTag.volume_profile_statistics);
@@ -813,7 +863,7 @@
         {
             return;
         }
-        ((VolumeRebalanceStatusModel)getWindow()).cancelRefresh();
+        ((VolumeRebalanceStatusModel) getWindow()).cancelRefresh();
         cancel();
     }
 
@@ -829,14 +879,14 @@
         for (Object item : getSelectedItems()) {
             GlusterVolumeEntity volume = (GlusterVolumeEntity) item;
             volumesForOptimiseForVirtStore.add(volume);
-            if(volume.getReplicaCount() != 3) {
+            if (volume.getReplicaCount() != 3) {
                 discouragedConfigVolumeNamesBuilder.append(volume.getName() + 
"\n");//$NON-NLS-1$
                 isDiscouragedVolumePresent = true;
             }
         }
         
discouragedConfigVolumeNamesBuilder.append(constants.optimiseForVirtStoreContinueMessage());
 
-        if(isDiscouragedVolumePresent) {
+        if (isDiscouragedVolumePresent) {
             ConfirmationModel cModel = new ConfirmationModel();
 
             cModel.setMessage(discouragedConfigVolumeNamesBuilder.toString());
@@ -857,7 +907,7 @@
     }
 
     private void optimizeVolumesForVirtStore(final List<GlusterVolumeEntity> 
volumeList) {
-        if(getConfirmWindow() != null) {
+        if (getConfirmWindow() != null) {
             setConfirmWindow(null);
         }
         AsyncQuery aQuery = new AsyncQuery();
@@ -888,20 +938,25 @@
                                 {
                                     Guid volumeId = volume.getId();
 
-                                    list.add(new 
GlusterVolumeOptionParameters(getOption(volumeId, "group", 
optionGroupVirt)));//$NON-NLS-1$
+                                    list.add(new 
GlusterVolumeOptionParameters(getOption(volumeId,
+                                            "group", 
optionGroupVirt)));//$NON-NLS-1$
 
-                                    list.add(new 
GlusterVolumeOptionParameters(getOption(volumeId, "storage.owner-uid", 
optionOwnerUserVirt)));//$NON-NLS-1$
+                                    list.add(new 
GlusterVolumeOptionParameters(getOption(volumeId,
+                                            "storage.owner-uid", 
optionOwnerUserVirt)));//$NON-NLS-1$
 
-                                    list.add(new 
GlusterVolumeOptionParameters(getOption(volumeId, "storage.owner-gid", 
optionOwnerGroupVirt)));//$NON-NLS-1$
+                                    list.add(new 
GlusterVolumeOptionParameters(getOption(volumeId,
+                                            "storage.owner-gid", 
optionOwnerGroupVirt)));//$NON-NLS-1$
 
-                                    final GlusterVolumeOptionEntity 
checkOption = getOption(volumeId, "network.ping-timeout", 
"10");//$NON-NLS-1$//$NON-NLS-2$
-                                    
List<PredicateFilter<GlusterVolumeOptionEntity>> predicaetFilters = 
Collections.singletonList(new PredicateFilter<GlusterVolumeOptionEntity>(new 
Predicate<GlusterVolumeOptionEntity>() {
-                                        @Override
-                                        public boolean 
evaluate(GlusterVolumeOptionEntity obj) {
-                                            return 
obj.getKey().equalsIgnoreCase(checkOption.getKey());
-                                        }
-                                    }));
-                                    if(!isOptionEnabledOnVolume(volume, 
predicaetFilters)) {
+                                    final GlusterVolumeOptionEntity 
checkOption =
+                                            getOption(volumeId, 
"network.ping-timeout", "10");//$NON-NLS-1$//$NON-NLS-2$
+                                    
List<PredicateFilter<GlusterVolumeOptionEntity>> predicaetFilters =
+                                            Collections.singletonList(new 
PredicateFilter<GlusterVolumeOptionEntity>(new 
Predicate<GlusterVolumeOptionEntity>() {
+                                                @Override
+                                                public boolean 
evaluate(GlusterVolumeOptionEntity obj) {
+                                                    return 
obj.getKey().equalsIgnoreCase(checkOption.getKey());
+                                                }
+                                            }));
+                                    if (!isOptionEnabledOnVolume(volume, 
predicaetFilters)) {
                                         list.add(new 
GlusterVolumeOptionParameters(checkOption));//$NON-NLS-1$
                                     }
                                 }
@@ -909,28 +964,33 @@
                             }
                         };
 
-                        AsyncDataProvider.getInstance().getConfigFromCache(new 
GetConfigurationValueParameters(ConfigurationValues.GlusterVolumeOptionOwnerGroupVirtValue,
-                                                                               
                  
AsyncDataProvider.getInstance().getDefaultConfigurationVersion()),
-                                aQueryInner1);
+                        AsyncDataProvider.getInstance()
+                                .getConfigFromCache(new 
GetConfigurationValueParameters(ConfigurationValues.GlusterVolumeOptionOwnerGroupVirtValue,
+                                        
AsyncDataProvider.getInstance().getDefaultConfigurationVersion()),
+                                        aQueryInner1);
                     }
                 };
-                AsyncDataProvider.getInstance().getConfigFromCache(new 
GetConfigurationValueParameters(ConfigurationValues.GlusterVolumeOptionOwnerUserVirtValue,
-                                                                               
          AsyncDataProvider.getInstance().getDefaultConfigurationVersion()),
-                        aQueryInner);
+                AsyncDataProvider.getInstance()
+                        .getConfigFromCache(new 
GetConfigurationValueParameters(ConfigurationValues.GlusterVolumeOptionOwnerUserVirtValue,
+                                
AsyncDataProvider.getInstance().getDefaultConfigurationVersion()),
+                                aQueryInner);
             }
         };
-        AsyncDataProvider.getInstance().getConfigFromCache(new 
GetConfigurationValueParameters(ConfigurationValues.GlusterVolumeOptionGroupVirtValue,
-                                                                               
  AsyncDataProvider.getInstance().getDefaultConfigurationVersion()),
-                aQuery);
+        AsyncDataProvider.getInstance()
+                .getConfigFromCache(new 
GetConfigurationValueParameters(ConfigurationValues.GlusterVolumeOptionGroupVirtValue,
+                        
AsyncDataProvider.getInstance().getDefaultConfigurationVersion()),
+                        aQuery);
     }
 
-    private boolean isOptionEnabledOnVolume(GlusterVolumeEntity volume, 
List<PredicateFilter<GlusterVolumeOptionEntity>> predicates) {
-        List<GlusterVolumeOptionEntity> volumeOptionsEnabled = new 
ArrayList<GlusterVolumeOptionEntity>(volume.getOptions());
+    private boolean isOptionEnabledOnVolume(GlusterVolumeEntity volume,
+            List<PredicateFilter<GlusterVolumeOptionEntity>> predicates) {
+        List<GlusterVolumeOptionEntity> volumeOptionsEnabled =
+                new ArrayList<GlusterVolumeOptionEntity>(volume.getOptions());
         List<GlusterVolumeOptionEntity> filteredOptions = volumeOptionsEnabled;
-        for(PredicateFilter<GlusterVolumeOptionEntity> predicate  : 
predicates) {
-             filteredOptions = ListUtils.filter(filteredOptions, predicate);
+        for (PredicateFilter<GlusterVolumeOptionEntity> predicate : 
predicates) {
+            filteredOptions = ListUtils.filter(filteredOptions, predicate);
         }
-        if(filteredOptions.size() > 0) {
+        if (filteredOptions.size() > 0) {
             return true;
         }
         return false;
@@ -1027,7 +1087,6 @@
         
Frontend.getInstance().runMultipleAction(VdcActionType.StartGlusterVolume, 
list);
     }
 
-
     private void onCreateVolume() {
         VolumeModel volumeModel = (VolumeModel) getWindow();
 
@@ -1088,14 +1147,17 @@
         CreateGlusterVolumeParameters parameter =
                 new CreateGlusterVolumeParameters(volume, 
volumeModel.isForceAddBricks());
 
-        Frontend.getInstance().runAction(VdcActionType.CreateGlusterVolume, 
parameter, new IFrontendActionAsyncCallback() {
+        Frontend.getInstance().runAction(VdcActionType.CreateGlusterVolume,
+                parameter,
+                new IFrontendActionAsyncCallback() {
 
-            @Override
-            public void executed(FrontendActionAsyncResult result) {
-                VolumeListModel localModel = (VolumeListModel) 
result.getState();
-                localModel.postOnCreateVolume(result.getReturnValue(), volume);
-            }
-        }, this);
+                    @Override
+                    public void executed(FrontendActionAsyncResult result) {
+                        VolumeListModel localModel = (VolumeListModel) 
result.getState();
+                        localModel.postOnCreateVolume(result.getReturnValue(), 
volume);
+                    }
+                },
+                this);
     }
 
     public void postOnCreateVolume(VdcReturnValueBase returnValue, 
GlusterVolumeEntity volume)
diff --git 
a/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/place/WebAdminApplicationPlaces.java
 
b/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/place/WebAdminApplicationPlaces.java
index 776698c..459b9cb 100644
--- 
a/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/place/WebAdminApplicationPlaces.java
+++ 
b/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/place/WebAdminApplicationPlaces.java
@@ -311,6 +311,8 @@
 
     public static final String volumeGeoRepSubTabPlace = volumeMainTabPlace + 
SUB_TAB_PREFIX + "geo_rep"; //$NON-NLS-1$
 
+    public static final String volumeSnapshotSubTabPlace = volumeMainTabPlace 
+ SUB_TAB_PREFIX + "volume_snapshots"; //$NON-NLS-1$
+
     // Disk
 
     public static final String diskGeneralSubTabPlace = diskMainTabPlace + 
SUB_TAB_PREFIX + "general"; //$NON-NLS-1$
@@ -322,7 +324,6 @@
     public static final String diskStorageSubTabPlace = diskMainTabPlace + 
SUB_TAB_PREFIX + "storage"; //$NON-NLS-1$
 
     public static final String diskPermissionSubTabPlace = diskMainTabPlace + 
SUB_TAB_PREFIX + "permissions"; //$NON-NLS-1$
-
 
     // Network
     public static final String networkGeneralSubTabPlace = networkMainTabPlace 
+ SUB_TAB_PREFIX + "general"; //$NON-NLS-1$
@@ -347,7 +348,6 @@
 
     public static final String networkPermissionSubTabPlace = 
networkMainTabPlace + SUB_TAB_PREFIX
             + "permissions"; //$NON-NLS-1$
-
 
     // Provider
     public static final String providerGeneralSubTabPlace = 
providerMainTabPlace + SUB_TAB_PREFIX + "general"; //$NON-NLS-1$
diff --git 
a/frontend/webadmin/modules/uicompat/src/main/java/org/ovirt/engine/ui/uicompat/LocalizedEnums.java
 
b/frontend/webadmin/modules/uicompat/src/main/java/org/ovirt/engine/ui/uicompat/LocalizedEnums.java
index 2650117..7b99c35 100644
--- 
a/frontend/webadmin/modules/uicompat/src/main/java/org/ovirt/engine/ui/uicompat/LocalizedEnums.java
+++ 
b/frontend/webadmin/modules/uicompat/src/main/java/org/ovirt/engine/ui/uicompat/LocalizedEnums.java
@@ -435,6 +435,10 @@
 
     String AuditLogType___REMOVE_GLUSTER_VOLUME_BRICKS_NOT_FOUND_FROM_CLI();
 
+    String AuditLogType___GLUSTER_VOLUME_SNAPSHOT_CREATED();
+
+    String AuditLogType___GLUSTER_VOLUME_SNAPSHOT_CREATE_FAILED();
+
     String VdcActionType___ActivateVds();
 
     String VdcActionType___RecoveryStoragePool();
@@ -720,6 +724,8 @@
 
     String VdcActionType___StartRebalanceGlusterVolume();
 
+    String VdcActionType___CreateGlusterVolumeSnapshot();
+
     String VdcActionType___ReplaceGlusterVolumeBrick();
 
     String VdcActionType___GlusterHostAdd();
diff --git 
a/frontend/webadmin/modules/uicompat/src/main/resources/org/ovirt/engine/ui/uicompat/LocalizedEnums.properties
 
b/frontend/webadmin/modules/uicompat/src/main/resources/org/ovirt/engine/ui/uicompat/LocalizedEnums.properties
index f50b0f9..091004c 100644
--- 
a/frontend/webadmin/modules/uicompat/src/main/resources/org/ovirt/engine/ui/uicompat/LocalizedEnums.properties
+++ 
b/frontend/webadmin/modules/uicompat/src/main/resources/org/ovirt/engine/ui/uicompat/LocalizedEnums.properties
@@ -217,6 +217,8 @@
 AuditLogType___GLUSTER_BRICK_STATUS_CHANGED=Detected change in status of brick
 AuditLogType___GLUSTER_VOLUME_REBALANCE_NOT_FOUND_FROM_CLI=Could not find 
information for rebalance on volume from CLI. Marking it as unknown.
 AuditLogType___REMOVE_GLUSTER_VOLUME_BRICKS_NOT_FOUND_FROM_CLI=Could not find 
information for remove brick on volume from CLI. Marking it as unknown.
+AuditLogType___GLUSTER_VOLUME_SNAPSHOT_CREATED=Snapshot created for the volume
+AuditLogType___GLUSTER_VOLUME_SNAPSHOT_CREATE_FAILED=Failed create snapshot 
for the volume
 
 
 VdcActionType___ActivateVds=Activate Host
@@ -335,6 +337,7 @@
 VdcActionType___GlusterVolumeRemoveBricks=Remove Gluster Volume Bricks
 VdcActionType___AddBricksToGlusterVolume=Add Brick To Gluster Volume
 VdcActionType___StartRebalanceGlusterVolume=Start Rebalance Gluster Volume
+VdcActionType___CreateGlusterVolumeSnapshot=Create Gluster Volume Snapshot
 VdcActionType___ReplaceGlusterVolumeBrick=Start Gluster Volume Replace Brick
 VdcActionType___GlusterHostAdd=Add Gluster server
 vdcActionType___StartGlusterVolumeProfile=Start Gluster Volume Profile
diff --git 
a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/ApplicationConstants.java
 
b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/ApplicationConstants.java
index f1d55e4..acab44f 100644
--- 
a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/ApplicationConstants.java
+++ 
b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/ApplicationConstants.java
@@ -106,6 +106,9 @@
     @DefaultStringValue("Geo-Replication")
     String volumeGeoRepSubTabLabel();
 
+    @DefaultStringValue("Snapshots")
+    String volumeSnapshotSubTabLabel();
+
     @DefaultStringValue("Destination Host")
     String volumeSubTabGeoRepSlaveClusterHostColumn();
 
@@ -819,7 +822,8 @@
     @DefaultStringValue("CPU Threads")
     String clusterPopupCpuThreadsPanelTitle();
 
-    @DefaultStringValue("Allow guests to use host threads as virtual CPU 
cores, utilizing AMD Clustered MultiThreading or Intel" +
+    @DefaultStringValue("Allow guests to use host threads as virtual CPU 
cores, utilizing AMD Clustered MultiThreading or Intel"
+            +
             " Hyper-Threading technology on the virtualization host. Enabling 
this option may be useful for less" +
             " CPU-intensive workloads, or to run guests with CPU 
configurations that would otherwise be restricted.")
     String clusterPopupCpuThreadsInfo();
@@ -3652,7 +3656,7 @@
     @DefaultStringValue("Remove brick in progress but status unknown. Unable 
to fetch the status at the moment.")
     String removeBrickStatusUnknown();
 
-    //Volume Rebalance Status Table Columns
+    // Volume Rebalance Status Table Columns
     @DefaultStringValue("Host")
     String rebalanceSessionHost();
 
@@ -3816,11 +3820,10 @@
     @DefaultStringValue("Disk Snapshots")
     String snapshotsLabel();
 
-
     @DefaultStringValue("Attached by label")
     String attachedByLabel();
 
-    //Gluster Volume Profiling
+    // Gluster Volume Profiling
     @DefaultStringValue("File operation")
     String fileOperation();
 
@@ -3973,4 +3976,56 @@
 
     @DefaultStringValue("NUMA Support")
     String numaSupport();
+
+    // Volume snapshots
+
+    @DefaultStringValue("New")
+    String newVolumeSnapshot();
+
+    @DefaultStringValue("Snapshot")
+    String volumeSnapshotMainTabTitle();
+
+    @DefaultStringValue("Cluster")
+    String volumeClusterLabel();
+
+    @DefaultStringValue("Volume")
+    String volumeNameLabel();
+
+    @DefaultStringValue("Snapshot Name")
+    String volumeSnapshotNameLabel();
+
+    @DefaultStringValue("Description")
+    String volumeSnapshotDescriptionLabel();
+
+    @DefaultStringValue("Force snapshot creation")
+    String forceVolumeSnapshotCreationLabel();
+
+    @DefaultStringValue("Note: If Force snapshot creation option is selected" +
+            " and the server-side quorum is met, snapshot creation" +
+            "succeeds even if bricks are down.")
+    String volumeQuorumNote();
+
+    @DefaultStringValue("Name")
+    String volumeSnapshotName();
+
+    @DefaultStringValue("Description")
+    String volumeSnapshotDescription();
+
+    @DefaultStringValue("Creation Time")
+    String volumeSnapshotCreationTime();
+
+    @DefaultStringValue("Restore")
+    String restoreVolumeSnapshot();
+
+    @DefaultStringValue("Delete")
+    String removeVolumeSnapshot();
+
+    @DefaultStringValue("Remove All")
+    String removeAllVolumeSnapshots();
+
+    @DefaultStringValue("Activate")
+    String activateVolumeSnapshot();
+
+    @DefaultStringValue("Deactivate")
+    String deactivateVolumeSnapshot();
 }
diff --git 
a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/gin/ClientGinjectorExtension.java
 
b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/gin/ClientGinjectorExtension.java
index cb8f9cd..7b505cf 100644
--- 
a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/gin/ClientGinjectorExtension.java
+++ 
b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/gin/ClientGinjectorExtension.java
@@ -26,6 +26,7 @@
 import 
org.ovirt.engine.core.common.businessentities.gluster.GlusterServerService;
 import 
org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeEntity;
 import 
org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeOptionEntity;
+import 
org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeSnapshotEntity;
 import org.ovirt.engine.core.common.businessentities.network.ExternalSubnet;
 import org.ovirt.engine.core.common.businessentities.network.HostNetworkQos;
 import org.ovirt.engine.core.common.businessentities.network.Network;
@@ -78,6 +79,7 @@
 import org.ovirt.engine.ui.uicommonweb.models.gluster.VolumeGeneralModel;
 import org.ovirt.engine.ui.uicommonweb.models.gluster.VolumeGeoRepListModel;
 import org.ovirt.engine.ui.uicommonweb.models.gluster.VolumeParameterListModel;
+import 
org.ovirt.engine.ui.uicommonweb.models.gluster.GlusterVolumeSnapshotListModel;
 import org.ovirt.engine.ui.uicommonweb.models.hosts.HostBricksListModel;
 import org.ovirt.engine.ui.uicommonweb.models.hosts.HostEventListModel;
 import org.ovirt.engine.ui.uicommonweb.models.hosts.HostGeneralModel;
@@ -389,6 +391,8 @@
 
     SearchableDetailModelProvider<GlusterGeoRepSession, VolumeListModel, 
VolumeGeoRepListModel> getSubTabVolumeGeoRepModelProvider();
 
+    SearchableDetailModelProvider<GlusterVolumeSnapshotEntity, 
VolumeListModel, GlusterVolumeSnapshotListModel> 
getSubTabVolumeSnapshotModelProvider();
+
     // Disk
 
     DetailModelProvider<DiskListModel, DiskGeneralModel> 
getSubTabDiskGeneralModelProvider();
diff --git 
a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/gin/PresenterModule.java
 
b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/gin/PresenterModule.java
index 5284304..9a5fa0e 100644
--- 
a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/gin/PresenterModule.java
+++ 
b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/gin/PresenterModule.java
@@ -44,6 +44,7 @@
 import 
org.ovirt.engine.ui.webadmin.section.main.presenter.popup.gluster.AddBrickPopupPresenterWidget;
 import 
org.ovirt.engine.ui.webadmin.section.main.presenter.popup.gluster.BrickAdvancedDetailsPopupPresenterWidget;
 import 
org.ovirt.engine.ui.webadmin.section.main.presenter.popup.gluster.DetachGlusterHostsPopupPresenterWidget;
+import 
org.ovirt.engine.ui.webadmin.section.main.presenter.popup.gluster.GlusterVolumeSnapshotCreatePopupPresenterWidget;
 import 
org.ovirt.engine.ui.webadmin.section.main.presenter.popup.gluster.RemoveBrickPopupPresenterWidget;
 import 
org.ovirt.engine.ui.webadmin.section.main.presenter.popup.gluster.RemoveBrickStatusPopupPresenterWidget;
 import 
org.ovirt.engine.ui.webadmin.section.main.presenter.popup.gluster.ReplaceBrickPopupPresenterWidget;
@@ -169,6 +170,7 @@
 import 
org.ovirt.engine.ui.webadmin.section.main.presenter.tab.gluster.SubTabVolumeGeoRepPresenter;
 import 
org.ovirt.engine.ui.webadmin.section.main.presenter.tab.gluster.SubTabVolumeParameterPresenter;
 import 
org.ovirt.engine.ui.webadmin.section.main.presenter.tab.gluster.SubTabVolumePermissionPresenter;
+import 
org.ovirt.engine.ui.webadmin.section.main.presenter.tab.gluster.SubTabGlusterVolumeSnapshotPresenter;
 import 
org.ovirt.engine.ui.webadmin.section.main.presenter.tab.gluster.VolumeSubTabPanelPresenter;
 import 
org.ovirt.engine.ui.webadmin.section.main.presenter.tab.host.HostSubTabPanelPresenter;
 import 
org.ovirt.engine.ui.webadmin.section.main.presenter.tab.host.SubTabHostBrickPresenter;
@@ -283,6 +285,7 @@
 import 
org.ovirt.engine.ui.webadmin.section.main.view.popup.gluster.AddBrickPopupView;
 import 
org.ovirt.engine.ui.webadmin.section.main.view.popup.gluster.BrickAdvancedDetailsPopupView;
 import 
org.ovirt.engine.ui.webadmin.section.main.view.popup.gluster.DetachGlusterHostsPopupView;
+import 
org.ovirt.engine.ui.webadmin.section.main.view.popup.gluster.GlusterVolumeSnapshotCreatePopupView;
 import 
org.ovirt.engine.ui.webadmin.section.main.view.popup.gluster.RemoveBrickPopupView;
 import 
org.ovirt.engine.ui.webadmin.section.main.view.popup.gluster.RemoveBrickStatusPopupView;
 import 
org.ovirt.engine.ui.webadmin.section.main.view.popup.gluster.ReplaceBrickPopupView;
@@ -414,6 +417,7 @@
 import 
org.ovirt.engine.ui.webadmin.section.main.view.tab.gluster.SubTabVolumeGeoRepView;
 import 
org.ovirt.engine.ui.webadmin.section.main.view.tab.gluster.SubTabVolumeParameterView;
 import 
org.ovirt.engine.ui.webadmin.section.main.view.tab.gluster.SubTabVolumePermissionView;
+import 
org.ovirt.engine.ui.webadmin.section.main.view.tab.gluster.SubTabGlusterVolumeSnapshotView;
 import 
org.ovirt.engine.ui.webadmin.section.main.view.tab.gluster.VolumeSubTabPanelView;
 import 
org.ovirt.engine.ui.webadmin.section.main.view.tab.host.HostSubTabPanelView;
 import 
org.ovirt.engine.ui.webadmin.section.main.view.tab.host.SubTabHostBrickView;
@@ -782,6 +786,9 @@
                 SubTabClusterCpuProfilePresenter.ViewDef.class,
                 SubTabClusterCpuProfileView.class,
                 SubTabClusterCpuProfilePresenter.ProxyDef.class);
+        
bindPresenterWidget(GlusterVolumeSnapshotCreatePopupPresenterWidget.class,
+                GlusterVolumeSnapshotCreatePopupPresenterWidget.ViewDef.class,
+                GlusterVolumeSnapshotCreatePopupView.class);
 
         // Host
         bindPresenter(HostSubTabPanelPresenter.class,
@@ -866,7 +873,6 @@
                 SubTabVirtualMachineEventPresenter.ViewDef.class,
                 SubTabVirtualMachineEventView.class,
                 SubTabVirtualMachineEventPresenter.ProxyDef.class);
-
 
         // Pool
         bindPresenter(PoolSubTabPanelPresenter.class,
@@ -1395,7 +1401,7 @@
                 QuotaPopupPresenterWidget.ViewDef.class,
                 QuotaPopupView.class);
 
-        //Network QoS
+        // Network QoS
         bindPresenterWidget(NetworkQoSPopupPresenterWidget.class,
                 NetworkQoSPopupPresenterWidget.ViewDef.class,
                 NetworkQoSPopupView.class);
@@ -1462,6 +1468,11 @@
                 SubTabVolumeEventView.class,
                 SubTabVolumeEventPresenter.ProxyDef.class);
 
+        bindPresenter(SubTabGlusterVolumeSnapshotPresenter.class,
+                SubTabGlusterVolumeSnapshotPresenter.ViewDef.class,
+                SubTabGlusterVolumeSnapshotView.class,
+                SubTabGlusterVolumeSnapshotPresenter.ProxyDef.class);
+
         bindPresenterWidget(AddBrickPopupPresenterWidget.class,
                 AddBrickPopupPresenterWidget.ViewDef.class,
                 AddBrickPopupView.class);
diff --git 
a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/gin/uicommon/VolumeModule.java
 
b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/gin/uicommon/VolumeModule.java
index 87f7789..ac1a2dc 100644
--- 
a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/gin/uicommon/VolumeModule.java
+++ 
b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/gin/uicommon/VolumeModule.java
@@ -6,6 +6,7 @@
 import 
org.ovirt.engine.core.common.businessentities.gluster.GlusterGeoRepSession;
 import 
org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeEntity;
 import 
org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeOptionEntity;
+import 
org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeSnapshotEntity;
 import 
org.ovirt.engine.ui.common.presenter.AbstractModelBoundPopupPresenterWidget;
 import 
org.ovirt.engine.ui.common.presenter.popup.DefaultConfirmationPopupPresenterWidget;
 import 
org.ovirt.engine.ui.common.presenter.popup.RemoveConfirmationPopupPresenterWidget;
@@ -20,6 +21,7 @@
 import org.ovirt.engine.ui.uicommonweb.models.ConfirmationModel;
 import org.ovirt.engine.ui.uicommonweb.models.Model;
 import org.ovirt.engine.ui.uicommonweb.models.configure.PermissionListModel;
+import 
org.ovirt.engine.ui.uicommonweb.models.gluster.GlusterVolumeSnapshotListModel;
 import org.ovirt.engine.ui.uicommonweb.models.gluster.VolumeBrickListModel;
 import org.ovirt.engine.ui.uicommonweb.models.gluster.VolumeEventListModel;
 import org.ovirt.engine.ui.uicommonweb.models.gluster.VolumeGeneralModel;
@@ -29,6 +31,7 @@
 import 
org.ovirt.engine.ui.webadmin.section.main.presenter.popup.event.EventPopupPresenterWidget;
 import 
org.ovirt.engine.ui.webadmin.section.main.presenter.popup.gluster.AddBrickPopupPresenterWidget;
 import 
org.ovirt.engine.ui.webadmin.section.main.presenter.popup.gluster.BrickAdvancedDetailsPopupPresenterWidget;
+import 
org.ovirt.engine.ui.webadmin.section.main.presenter.popup.gluster.GlusterVolumeSnapshotCreatePopupPresenterWidget;
 import 
org.ovirt.engine.ui.webadmin.section.main.presenter.popup.gluster.RemoveBrickPopupPresenterWidget;
 import 
org.ovirt.engine.ui.webadmin.section.main.presenter.popup.gluster.RemoveBrickStatusPopupPresenterWidget;
 import 
org.ovirt.engine.ui.webadmin.section.main.presenter.popup.gluster.ReplaceBrickPopupPresenterWidget;
@@ -60,36 +63,40 @@
             final Provider<VolumeListModel> modelProvider,
             final Provider<CommonModel> commonModelProvider) {
         MainTabModelProvider<GlusterVolumeEntity, VolumeListModel> result =
-                new MainTabModelProvider<GlusterVolumeEntity, 
VolumeListModel>(eventBus, defaultConfirmPopupProvider,
+                new MainTabModelProvider<GlusterVolumeEntity, 
VolumeListModel>(eventBus,
+                        defaultConfirmPopupProvider,
                         commonModelProvider) {
-            @Override
-            public AbstractModelBoundPopupPresenterWidget<? extends Model, ?> 
getModelPopup(VolumeListModel source,
-                    UICommand lastExecutedCommand, Model windowModel) {
-                if (lastExecutedCommand == getModel().getNewVolumeCommand()) {
-                    return popupProvider.get();
-                }
-                else if (lastExecutedCommand == 
getModel().getStatusRebalanceCommand() || 
lastExecutedCommand.getName().equals("onStopRebalance")) {//$NON-NLS-1$
-                    return rebalanceStatusPopupProvider.get();
-                }
-                else if(lastExecutedCommand == 
getModel().getShowVolumeProfileDetailsCommand() || 
lastExecutedCommand.getName().equals("showProfileDetails")) {//$NON-NLS-1$
-                    return volumeProfileStatsPopupProvider.get();
-                }
-                else {
-                    return super.getModelPopup(source, lastExecutedCommand, 
windowModel);
-                }
-            }
+                    @Override
+                    public AbstractModelBoundPopupPresenterWidget<? extends 
Model, ?> getModelPopup(VolumeListModel source,
+                            UICommand lastExecutedCommand,
+                            Model windowModel) {
+                        if (lastExecutedCommand == 
getModel().getNewVolumeCommand()) {
+                            return popupProvider.get();
+                        }
+                        else if (lastExecutedCommand == 
getModel().getStatusRebalanceCommand()
+                                || 
lastExecutedCommand.getName().equals("onStopRebalance")) {//$NON-NLS-1$
+                            return rebalanceStatusPopupProvider.get();
+                        }
+                        else if (lastExecutedCommand == 
getModel().getShowVolumeProfileDetailsCommand()
+                                || 
lastExecutedCommand.getName().equals("showProfileDetails")) {//$NON-NLS-1$
+                            return volumeProfileStatsPopupProvider.get();
+                        }
+                        else {
+                            return super.getModelPopup(source, 
lastExecutedCommand, windowModel);
+                        }
+                    }
 
-            @Override
-            public AbstractModelBoundPopupPresenterWidget<? extends 
ConfirmationModel, ?> getConfirmModelPopup(VolumeListModel source,
-                    UICommand lastExecutedCommand) {
-                if (lastExecutedCommand == getModel().getStopCommand()
-                        || lastExecutedCommand == 
getModel().getRemoveVolumeCommand()) {
-                    return removeConfirmPopupProvider.get();
-                } else {
-                    return super.getConfirmModelPopup(source, 
lastExecutedCommand);
-                }
-            }
-        };
+                    @Override
+                    public AbstractModelBoundPopupPresenterWidget<? extends 
ConfirmationModel, ?> getConfirmModelPopup(VolumeListModel source,
+                            UICommand lastExecutedCommand) {
+                        if (lastExecutedCommand == getModel().getStopCommand()
+                                || lastExecutedCommand == 
getModel().getRemoveVolumeCommand()) {
+                            return removeConfirmPopupProvider.get();
+                        } else {
+                            return super.getConfirmModelPopup(source, 
lastExecutedCommand);
+                        }
+                    }
+                };
         result.setModelProvider(modelProvider);
         return result;
     }
@@ -108,39 +115,71 @@
             final Provider<VolumeBrickListModel> modelProvider) {
         SearchableDetailTabModelProvider<GlusterBrickEntity, VolumeListModel, 
VolumeBrickListModel> result =
                 new SearchableDetailTabModelProvider<GlusterBrickEntity, 
VolumeListModel, VolumeBrickListModel>(
-                eventBus, defaultConfirmPopupProvider) {
-            @Override
-            public AbstractModelBoundPopupPresenterWidget<? extends Model, ?> 
getModelPopup(VolumeBrickListModel source,
-                    UICommand lastExecutedCommand,
-                    Model windowModel) {
-                if (lastExecutedCommand == getModel().getAddBricksCommand()) {
-                    return addBrickPopupProvider.get();
-                } else if (lastExecutedCommand == 
getModel().getRemoveBricksCommand()) {
-                    return removeBrickPopupProvider.get();
-                } else if (lastExecutedCommand == 
getModel().getStatusRemoveBricksCommand()) {
-                    return removeBricksStatusPopupProvider.get();
-                }else if 
(lastExecutedCommand.getName().equals("OnStopRemoveBricks")) {  //$NON-NLS-1$
-                    return removeBricksStatusPopupProvider.get();
-                } else if (lastExecutedCommand == 
getModel().getReplaceBrickCommand()) {
-                    return replaceBrickPopupProvider.get();
-                } else if (lastExecutedCommand == 
getModel().getBrickAdvancedDetailsCommand()) {
-                    return brickDetailsPopupProvider.get();
-                } else {
-                    return super.getModelPopup(source, lastExecutedCommand, 
windowModel);
-                }
-            }
+                        eventBus, defaultConfirmPopupProvider) {
+                    @Override
+                    public AbstractModelBoundPopupPresenterWidget<? extends 
Model, ?> getModelPopup(VolumeBrickListModel source,
+                            UICommand lastExecutedCommand,
+                            Model windowModel) {
+                        if (lastExecutedCommand == 
getModel().getAddBricksCommand()) {
+                            return addBrickPopupProvider.get();
+                        } else if (lastExecutedCommand == 
getModel().getRemoveBricksCommand()) {
+                            return removeBrickPopupProvider.get();
+                        } else if (lastExecutedCommand == 
getModel().getStatusRemoveBricksCommand()) {
+                            return removeBricksStatusPopupProvider.get();
+                        } else if 
(lastExecutedCommand.getName().equals("OnStopRemoveBricks")) { //$NON-NLS-1$
+                            return removeBricksStatusPopupProvider.get();
+                        } else if (lastExecutedCommand == 
getModel().getReplaceBrickCommand()) {
+                            return replaceBrickPopupProvider.get();
+                        } else if (lastExecutedCommand == 
getModel().getBrickAdvancedDetailsCommand()) {
+                            return brickDetailsPopupProvider.get();
+                        } else {
+                            return super.getModelPopup(source, 
lastExecutedCommand, windowModel);
+                        }
+                    }
 
-            @Override
-            public AbstractModelBoundPopupPresenterWidget<? extends 
ConfirmationModel, ?> getConfirmModelPopup(VolumeBrickListModel source,
-                    UICommand lastExecutedCommand) {
-                if (lastExecutedCommand == 
getModel().getRemoveBricksCommand()) {
-                    return removeConfirmPopupProvider.get();
-                } else {
-                    return super.getConfirmModelPopup(source, 
lastExecutedCommand);
-                }
-            }
+                    @Override
+                    public AbstractModelBoundPopupPresenterWidget<? extends 
ConfirmationModel, ?> getConfirmModelPopup(VolumeBrickListModel source,
+                            UICommand lastExecutedCommand) {
+                        if (lastExecutedCommand == 
getModel().getRemoveBricksCommand()) {
+                            return removeConfirmPopupProvider.get();
+                        } else {
+                            return super.getConfirmModelPopup(source, 
lastExecutedCommand);
+                        }
+                    }
 
-        };
+                };
+        result.setMainModelProvider(mainModelProvider);
+        result.setModelProvider(modelProvider);
+        return result;
+    }
+
+    @Provides
+    @Singleton
+    public SearchableDetailModelProvider<GlusterVolumeSnapshotEntity, 
VolumeListModel, GlusterVolumeSnapshotListModel> 
getVolumeSnapshotListProvider(EventBus eventBus,
+            Provider<DefaultConfirmationPopupPresenterWidget> 
defaultConfirmPopupProvider,
+            final Provider<VolumeListModel> mainModelProvider,
+            final Provider<GlusterVolumeSnapshotListModel> modelProvider,
+            final Provider<GlusterVolumeSnapshotCreatePopupPresenterWidget> 
snapshotPopupProvider) {
+        SearchableDetailTabModelProvider<GlusterVolumeSnapshotEntity, 
VolumeListModel, GlusterVolumeSnapshotListModel> result =
+                new 
SearchableDetailTabModelProvider<GlusterVolumeSnapshotEntity, VolumeListModel, 
GlusterVolumeSnapshotListModel>(
+                        eventBus, defaultConfirmPopupProvider) {
+                    @Override
+                    public AbstractModelBoundPopupPresenterWidget<? extends 
Model, ?> getModelPopup(GlusterVolumeSnapshotListModel source,
+                            UICommand lastExecutedCommand,
+                            Model windowModel) {
+                        if (lastExecutedCommand == 
getModel().getNewSnapshotCommand()) {
+                            return snapshotPopupProvider.get();
+                        }
+                        return super.getModelPopup(source, 
lastExecutedCommand, windowModel);
+                    }
+
+                    @Override
+                    public AbstractModelBoundPopupPresenterWidget<? extends 
ConfirmationModel, ?> getConfirmModelPopup(GlusterVolumeSnapshotListModel 
source,
+                            UICommand lastExecutedCommand) {
+                        return super.getConfirmModelPopup(source, 
lastExecutedCommand);
+                    }
+
+                };
         result.setMainModelProvider(mainModelProvider);
         result.setModelProvider(modelProvider);
         return result;
@@ -156,20 +195,20 @@
             final Provider<VolumeParameterListModel> modelProvider) {
         SearchableDetailTabModelProvider<GlusterVolumeOptionEntity, 
VolumeListModel, VolumeParameterListModel> result =
                 new 
SearchableDetailTabModelProvider<GlusterVolumeOptionEntity, VolumeListModel, 
VolumeParameterListModel>(
-                eventBus, defaultConfirmPopupProvider) {
-            @Override
-            public AbstractModelBoundPopupPresenterWidget<? extends Model, ?> 
getModelPopup(VolumeParameterListModel source,
-                    UICommand lastExecutedCommand,
-                    Model windowModel) {
-                if (lastExecutedCommand == 
getModel().getAddParameterCommand()) {
-                    return addParameterPopupProvider.get();
-                } else if (lastExecutedCommand == 
getModel().getEditParameterCommand()) {
-                    return editParameterPopupProvider.get();
-                } else {
-                    return super.getModelPopup(source, lastExecutedCommand, 
windowModel);
-                }
-            }
-        };
+                        eventBus, defaultConfirmPopupProvider) {
+                    @Override
+                    public AbstractModelBoundPopupPresenterWidget<? extends 
Model, ?> getModelPopup(VolumeParameterListModel source,
+                            UICommand lastExecutedCommand,
+                            Model windowModel) {
+                        if (lastExecutedCommand == 
getModel().getAddParameterCommand()) {
+                            return addParameterPopupProvider.get();
+                        } else if (lastExecutedCommand == 
getModel().getEditParameterCommand()) {
+                            return editParameterPopupProvider.get();
+                        } else {
+                            return super.getModelPopup(source, 
lastExecutedCommand, windowModel);
+                        }
+                    }
+                };
         result.setMainModelProvider(mainModelProvider);
         result.setModelProvider(modelProvider);
         return result;
@@ -184,18 +223,18 @@
             final Provider<VolumeEventListModel> modelProvider) {
         SearchableDetailTabModelProvider<AuditLog, VolumeListModel, 
VolumeEventListModel> result =
                 new SearchableDetailTabModelProvider<AuditLog, 
VolumeListModel, VolumeEventListModel>(
-                eventBus, defaultConfirmPopupProvider) {
-            @Override
-            public AbstractModelBoundPopupPresenterWidget<? extends Model, ?> 
getModelPopup(VolumeEventListModel source,
-                    UICommand lastExecutedCommand,
-                    Model windowModel) {
-                if 
(lastExecutedCommand.equals(getModel().getDetailsCommand())) {
-                    return eventPopupProvider.get();
-                } else {
-                    return super.getModelPopup(source, lastExecutedCommand, 
windowModel);
-                }
-            }
-        };
+                        eventBus, defaultConfirmPopupProvider) {
+                    @Override
+                    public AbstractModelBoundPopupPresenterWidget<? extends 
Model, ?> getModelPopup(VolumeEventListModel source,
+                            UICommand lastExecutedCommand,
+                            Model windowModel) {
+                        if 
(lastExecutedCommand.equals(getModel().getDetailsCommand())) {
+                            return eventPopupProvider.get();
+                        } else {
+                            return super.getModelPopup(source, 
lastExecutedCommand, windowModel);
+                        }
+                    }
+                };
         result.setMainModelProvider(mainModelProvider);
         result.setModelProvider(modelProvider);
         return result;
@@ -208,18 +247,25 @@
         bind(VolumeBrickListModel.class).in(Singleton.class);
         bind(VolumeParameterListModel.class).in(Singleton.class);
         bind(VolumeEventListModel.class).in(Singleton.class);
-        bind(new 
TypeLiteral<PermissionListModel<VolumeListModel>>(){}).in(Singleton.class);
+        bind(new TypeLiteral<PermissionListModel<VolumeListModel>>() 
{}).in(Singleton.class);
+        bind(GlusterVolumeSnapshotListModel.class).in(Singleton.class);
 
         // Form Detail Models
-        bind(new TypeLiteral<DetailModelProvider<VolumeListModel, 
VolumeGeneralModel>>(){})
-            .to(new TypeLiteral<DetailTabModelProvider<VolumeListModel, 
VolumeGeneralModel>>(){}).in(Singleton.class);
+        bind(new TypeLiteral<DetailModelProvider<VolumeListModel, 
VolumeGeneralModel>>() {
+        })
+                .to(new TypeLiteral<DetailTabModelProvider<VolumeListModel, 
VolumeGeneralModel>>() {
+                }).in(Singleton.class);
         // Search-able Detail Models
-        bind(new 
TypeLiteral<SearchableDetailModelProvider<GlusterGeoRepSession, 
VolumeListModel, VolumeGeoRepListModel>>(){})
-           .to(new 
TypeLiteral<SearchableDetailTabModelProvider<GlusterGeoRepSession, 
VolumeListModel, VolumeGeoRepListModel>>(){})
-           .in(Singleton.class);
+        bind(new 
TypeLiteral<SearchableDetailModelProvider<GlusterGeoRepSession, 
VolumeListModel, VolumeGeoRepListModel>>() {
+        })
+                .to(new 
TypeLiteral<SearchableDetailTabModelProvider<GlusterGeoRepSession, 
VolumeListModel, VolumeGeoRepListModel>>() {
+                })
+                .in(Singleton.class);
         // Permission Detail Model
-        bind(new TypeLiteral<SearchableDetailModelProvider<Permissions, 
VolumeListModel, PermissionListModel<VolumeListModel>>>(){})
-           .to(new 
TypeLiteral<PermissionModelProvider<VolumeListModel>>(){}).in(Singleton.class);
+        bind(new TypeLiteral<SearchableDetailModelProvider<Permissions, 
VolumeListModel, PermissionListModel<VolumeListModel>>>() {
+        })
+                .to(new 
TypeLiteral<PermissionModelProvider<VolumeListModel>>() {
+                }).in(Singleton.class);
     }
 
 }
diff --git 
a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/presenter/popup/gluster/GlusterVolumeSnapshotCreatePopupPresenterWidget.java
 
b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/presenter/popup/gluster/GlusterVolumeSnapshotCreatePopupPresenterWidget.java
new file mode 100644
index 0000000..ca5eb16
--- /dev/null
+++ 
b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/presenter/popup/gluster/GlusterVolumeSnapshotCreatePopupPresenterWidget.java
@@ -0,0 +1,34 @@
+package org.ovirt.engine.ui.webadmin.section.main.presenter.popup.gluster;
+
+import 
org.ovirt.engine.ui.common.presenter.AbstractModelBoundPopupPresenterWidget;
+import 
org.ovirt.engine.ui.common.presenter.popup.DefaultConfirmationPopupPresenterWidget;
+import 
org.ovirt.engine.ui.uicommonweb.models.gluster.GlusterVolumeSnapshotModel;
+import org.ovirt.engine.ui.uicompat.Event;
+import org.ovirt.engine.ui.uicompat.EventArgs;
+import org.ovirt.engine.ui.uicompat.IEventListener;
+
+import com.google.gwt.event.shared.EventBus;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+public class GlusterVolumeSnapshotCreatePopupPresenterWidget extends 
AbstractModelBoundPopupPresenterWidget<GlusterVolumeSnapshotModel, 
GlusterVolumeSnapshotCreatePopupPresenterWidget.ViewDef> {
+    @Inject
+    public GlusterVolumeSnapshotCreatePopupPresenterWidget(EventBus eventBus, 
ViewDef view, Provider<GlusterVolumeSnapshotCreatePopupPresenterWidget> 
snapshotPopupProvider, Provider<DefaultConfirmationPopupPresenterWidget> 
defaultConfirmPopupPrivder) {
+        super(eventBus, view);
+    }
+
+    @Override
+    public void init(final GlusterVolumeSnapshotModel model) {
+        super.init(model);
+        model.getForceCreate().getEntityChangedEvent().addListener(new 
IEventListener<EventArgs>() {
+            @Override
+            public void eventRaised(Event<? extends EventArgs> ev, Object 
sender, EventArgs args) {
+                
getView().setForceLabelVisibility(model.getForceCreate().getEntity());
+            }
+        });
+    }
+
+    public interface ViewDef extends 
AbstractModelBoundPopupPresenterWidget.ViewDef<GlusterVolumeSnapshotModel> {
+        public void setForceLabelVisibility(boolean visible);
+    }
+}
diff --git 
a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/presenter/tab/gluster/SubTabGlusterVolumeSnapshotPresenter.java
 
b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/presenter/tab/gluster/SubTabGlusterVolumeSnapshotPresenter.java
new file mode 100644
index 0000000..7220eda
--- /dev/null
+++ 
b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/presenter/tab/gluster/SubTabGlusterVolumeSnapshotPresenter.java
@@ -0,0 +1,58 @@
+package org.ovirt.engine.ui.webadmin.section.main.presenter.tab.gluster;
+
+import 
org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeEntity;
+import 
org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeSnapshotEntity;
+import org.ovirt.engine.ui.common.place.PlaceRequestFactory;
+import org.ovirt.engine.ui.common.presenter.AbstractSubTabPresenter;
+import org.ovirt.engine.ui.common.uicommon.model.SearchableDetailModelProvider;
+import org.ovirt.engine.ui.common.widget.tab.ModelBoundTabData;
+import 
org.ovirt.engine.ui.uicommonweb.models.gluster.GlusterVolumeSnapshotListModel;
+import org.ovirt.engine.ui.uicommonweb.models.volumes.VolumeListModel;
+import org.ovirt.engine.ui.uicommonweb.place.WebAdminApplicationPlaces;
+import org.ovirt.engine.ui.webadmin.ApplicationConstants;
+import 
org.ovirt.engine.ui.webadmin.section.main.presenter.tab.VolumeSelectionChangeEvent;
+
+import com.google.gwt.event.shared.EventBus;
+import com.google.inject.Inject;
+import com.gwtplatform.mvp.client.TabData;
+import com.gwtplatform.mvp.client.annotations.NameToken;
+import com.gwtplatform.mvp.client.annotations.ProxyCodeSplit;
+import com.gwtplatform.mvp.client.annotations.ProxyEvent;
+import com.gwtplatform.mvp.client.annotations.TabInfo;
+import com.gwtplatform.mvp.client.proxy.PlaceManager;
+import com.gwtplatform.mvp.client.proxy.TabContentProxyPlace;
+import com.gwtplatform.mvp.shared.proxy.PlaceRequest;
+
+public class SubTabGlusterVolumeSnapshotPresenter extends 
AbstractSubTabPresenter<GlusterVolumeEntity, VolumeListModel, 
GlusterVolumeSnapshotListModel, SubTabGlusterVolumeSnapshotPresenter.ViewDef, 
SubTabGlusterVolumeSnapshotPresenter.ProxyDef> {
+    @TabInfo(container = VolumeSubTabPanelPresenter.class)
+    static TabData getTabData(ApplicationConstants applicationConstants,
+            SearchableDetailModelProvider<GlusterVolumeSnapshotEntity, 
VolumeListModel, GlusterVolumeSnapshotListModel> modelProvider) {
+        return new 
ModelBoundTabData(applicationConstants.volumeSnapshotSubTabLabel(), 5, 
modelProvider);
+    }
+
+    @Inject
+    public SubTabGlusterVolumeSnapshotPresenter(EventBus eventBus, ViewDef 
view, ProxyDef proxy,
+            PlaceManager placeManager,
+            SearchableDetailModelProvider<GlusterVolumeSnapshotEntity, 
VolumeListModel, GlusterVolumeSnapshotListModel> modelProvider) {
+        super(eventBus, view, proxy, placeManager, modelProvider,
+                VolumeSubTabPanelPresenter.TYPE_SetTabContent);
+    }
+
+    @ProxyCodeSplit
+    @NameToken(WebAdminApplicationPlaces.volumeSnapshotSubTabPlace)
+    public interface ProxyDef extends 
TabContentProxyPlace<SubTabGlusterVolumeSnapshotPresenter> {
+    }
+
+    public interface ViewDef extends 
AbstractSubTabPresenter.ViewDef<GlusterVolumeEntity> {
+    }
+
+    @Override
+    protected PlaceRequest getMainTabRequest() {
+        return 
PlaceRequestFactory.get(WebAdminApplicationPlaces.volumeMainTabPlace);
+    }
+
+    @ProxyEvent
+    public void onVolumeSelectionChange(VolumeSelectionChangeEvent event) {
+        updateMainTabSelection(event.getSelectedItems());
+    }
+}
diff --git 
a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/popup/gluster/GlusterVolumeSnapshotCreatePopupView.java
 
b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/popup/gluster/GlusterVolumeSnapshotCreatePopupView.java
new file mode 100644
index 0000000..909e918
--- /dev/null
+++ 
b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/popup/gluster/GlusterVolumeSnapshotCreatePopupView.java
@@ -0,0 +1,124 @@
+package org.ovirt.engine.ui.webadmin.section.main.view.popup.gluster;
+
+import org.ovirt.engine.ui.common.idhandler.ElementIdHandler;
+import org.ovirt.engine.ui.common.idhandler.WithElementId;
+import org.ovirt.engine.ui.common.view.popup.AbstractModelBoundPopupView;
+import org.ovirt.engine.ui.common.widget.Align;
+import org.ovirt.engine.ui.common.widget.dialog.SimpleDialogPanel;
+import 
org.ovirt.engine.ui.common.widget.editor.generic.EntityModelCheckBoxEditor;
+import 
org.ovirt.engine.ui.common.widget.editor.generic.StringEntityModelLabelEditor;
+import 
org.ovirt.engine.ui.common.widget.editor.generic.StringEntityModelTextBoxEditor;
+import 
org.ovirt.engine.ui.uicommonweb.models.gluster.GlusterVolumeSnapshotModel;
+import org.ovirt.engine.ui.webadmin.ApplicationConstants;
+import org.ovirt.engine.ui.webadmin.ApplicationResources;
+import 
org.ovirt.engine.ui.webadmin.section.main.presenter.popup.gluster.GlusterVolumeSnapshotCreatePopupPresenterWidget;
+
+import com.google.gwt.core.shared.GWT;
+import com.google.gwt.editor.client.SimpleBeanEditorDriver;
+import com.google.gwt.event.shared.EventBus;
+import com.google.gwt.resources.client.CssResource;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.user.client.ui.TextArea;
+import com.google.inject.Inject;
+
+public class GlusterVolumeSnapshotCreatePopupView extends 
AbstractModelBoundPopupView<GlusterVolumeSnapshotModel> implements 
GlusterVolumeSnapshotCreatePopupPresenterWidget.ViewDef {
+    interface Driver extends 
SimpleBeanEditorDriver<GlusterVolumeSnapshotModel, 
GlusterVolumeSnapshotCreatePopupView> {
+    }
+
+    interface ViewUiBinder extends UiBinder<SimpleDialogPanel, 
GlusterVolumeSnapshotCreatePopupView> {
+        ViewUiBinder uiBinder = GWT.create(ViewUiBinder.class);
+    }
+
+    interface ViewIdHandler extends 
ElementIdHandler<GlusterVolumeSnapshotCreatePopupView> {
+        ViewIdHandler idHandler = GWT.create(ViewIdHandler.class);
+    }
+
+    @UiField
+    WidgetStyle style;
+
+    @UiField
+    @Path(value = "clusterName.entity")
+    @WithElementId
+    StringEntityModelLabelEditor clusterNameEditor;
+
+    @UiField
+    @Path(value = "volumeName.entity")
+    @WithElementId
+    StringEntityModelLabelEditor volumeNameEditor;
+
+    @UiField
+    @Path(value = "snapshotName.entity")
+    @WithElementId
+    StringEntityModelTextBoxEditor snapshotNameEditor;
+
+    @UiField
+    @Path(value = "description.entity")
+    @WithElementId
+    StringEntityModelTextBoxEditor snapshotDescriptionEditor;
+
+    @UiField(provided = true)
+    @Path(value = "forceCreate.entity")
+    @WithElementId
+    EntityModelCheckBoxEditor forceCreateEditor;
+
+    @UiField
+    @Ignore
+    TextArea forceWarningLabel;
+
+    private final ApplicationConstants constants;
+
+    private final Driver driver = GWT.create(Driver.class);
+
+    @Inject
+    public GlusterVolumeSnapshotCreatePopupView(EventBus eventBus,
+            ApplicationResources resources,
+            ApplicationConstants constants) {
+        super(eventBus, resources);
+        this.constants = constants;
+        initEditors();
+        initWidget(ViewUiBinder.uiBinder.createAndBindUi(this));
+        ViewIdHandler.idHandler.generateAndSetIds(this);
+        localize();
+        addStyles();
+        driver.initialize(this);
+        setTitle(constants.newVolumeSnapshot());
+    }
+
+    private void initEditors() {
+        forceCreateEditor = new EntityModelCheckBoxEditor(Align.RIGHT);
+    }
+
+    private void addStyles() {
+        
forceCreateEditor.addContentWidgetContainerStyleName(style.checkBoxEditorWidget());
+    }
+
+    private void localize() {
+        clusterNameEditor.setLabel(constants.volumeClusterLabel());
+        volumeNameEditor.setLabel(constants.volumeNameLabel());
+        snapshotNameEditor.setLabel(constants.volumeSnapshotNameLabel());
+        
snapshotDescriptionEditor.setLabel(constants.volumeSnapshotDescriptionLabel());
+        
forceCreateEditor.setLabel(constants.forceVolumeSnapshotCreationLabel());
+        forceWarningLabel.setText(constants.volumeQuorumNote());
+    }
+
+    @Override
+    public void edit(final GlusterVolumeSnapshotModel object) {
+        driver.edit(object);
+        setForceLabelVisibility(object.getForceCreate().getEntity());
+    }
+
+    @Override
+    public GlusterVolumeSnapshotModel flush() {
+        return driver.flush();
+    }
+
+    interface WidgetStyle extends CssResource {
+        String checkBoxEditorWidget();
+    }
+
+    @Override
+    public void setForceLabelVisibility(boolean visible) {
+        forceWarningLabel.setVisible(visible);
+    }
+}
diff --git 
a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/popup/gluster/GlusterVolumeSnapshotCreatePopupView.ui.xml
 
b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/popup/gluster/GlusterVolumeSnapshotCreatePopupView.ui.xml
new file mode 100644
index 0000000..c61f122
--- /dev/null
+++ 
b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/popup/gluster/GlusterVolumeSnapshotCreatePopupView.ui.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent";>
+<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
+       xmlns:g="urn:import:com.google.gwt.user.client.ui" 
xmlns:d="urn:import:org.ovirt.engine.ui.common.widget.dialog"
+       xmlns:ge="urn:import:org.ovirt.engine.ui.common.widget.editor.generic"
+       xmlns:e="urn:import:org.ovirt.engine.ui.common.widget.editor" 
xmlns:w="urn:import:org.ovirt.engine.ui.common.widget">
+
+       <ui:style
+               
type="org.ovirt.engine.ui.webadmin.section.main.view.popup.gluster.GlusterVolumeSnapshotCreatePopupView.WidgetStyle">
+               .forceWarningLabel {
+               width: 450px;
+               font-size: 13px;
+               left: 10px;
+               padding-left: 15px;
+               padding-bottom: 10px;
+               color: #FF0000;
+               }
+
+               .panelStyle{
+               width:470px;
+               }
+
+               .messageLabel {
+               color: #FF0000;
+               left: 10px;
+               padding-left:
+               5px;
+               }
+
+               .checkBoxEditorWidget{
+               width: 450px;
+               }
+       </ui:style>
+
+       <d:SimpleDialogPanel width="480px" height="400px">
+               <d:content>
+                       <g:FlowPanel addStyleNames="{style.panelStyle}">
+                               <ge:StringEntityModelLabelEditor
+                                       ui:field="clusterNameEditor" />
+                               <ge:StringEntityModelLabelEditor
+                                       ui:field="volumeNameEditor" />
+                               <ge:StringEntityModelTextBoxEditor
+                                       ui:field="snapshotNameEditor" />
+                               <ge:StringEntityModelTextBoxEditor
+                                       ui:field="snapshotDescriptionEditor" />
+                               <ge:EntityModelCheckBoxEditor 
ui:field="forceCreateEditor" />
+                               <g:FlowPanel addStyleNames="{style.panelStyle}">
+                                       <g:TextArea 
ui:field="forceWarningLabel" addStyleNames="{style.forceWarningLabel}" />
+                               </g:FlowPanel>
+                       </g:FlowPanel>
+               </d:content>
+       </d:SimpleDialogPanel>
+</ui:UiBinder>
\ No newline at end of file
diff --git 
a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/tab/MainTabVolumeView.java
 
b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/tab/MainTabVolumeView.java
index dd7087b..b1f6fd7 100644
--- 
a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/tab/MainTabVolumeView.java
+++ 
b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/tab/MainTabVolumeView.java
@@ -60,7 +60,8 @@
         statusColumn.makeSortable(new Comparator<GlusterVolumeEntity>() {
             @Override
             public int compare(GlusterVolumeEntity o1, GlusterVolumeEntity o2) 
{
-                return GlusterVolumeUtils.getVolumeStatus(o1).ordinal() - 
GlusterVolumeUtils.getVolumeStatus(o2).ordinal();
+                return GlusterVolumeUtils.getVolumeStatus(o1).ordinal()
+                        - GlusterVolumeUtils.getVolumeStatus(o2).ordinal();
             }
         });
         getTable().addColumn(statusColumn, constants.empty(), "30px"); 
//$NON-NLS-1$
@@ -142,11 +143,11 @@
         }, constants.volumeCapacity(), "60px");//$NON-NLS-1$
 
         getTable().addColumn(new VolumeActivityColumn<GlusterVolumeEntity>(new 
VolumeActivityCompositeCell<GlusterTaskSupport>(compositeList) {
-                @Override
-                protected boolean isVisible(GlusterTaskSupport value) {
-                    return !(value == null || value.getAsyncTask() == null);
-                }
-                }),
+            @Override
+            protected boolean isVisible(GlusterTaskSupport value) {
+                return !(value == null || value.getAsyncTask() == null);
+            }
+        }),
                 constants.activitiesOnVolume(),
                 "100px"); //$NON-NLS-1$
 
@@ -187,7 +188,8 @@
             }
         });
 
-        List<ActionButtonDefinition<GlusterVolumeEntity>> 
volumeProfilingActions = new 
LinkedList<ActionButtonDefinition<GlusterVolumeEntity>>();
+        List<ActionButtonDefinition<GlusterVolumeEntity>> 
volumeProfilingActions =
+                new LinkedList<ActionButtonDefinition<GlusterVolumeEntity>>();
         volumeProfilingActions.add(new 
WebAdminButtonDefinition<GlusterVolumeEntity>(constants.startVolumeProfiling()) 
{
             @Override
             protected UICommand resolveCommand() {
@@ -206,7 +208,26 @@
                 return getMainModel().getStopVolumeProfilingCommand();
             }
         });
-        getTable().addActionButton(new 
WebAdminMenuBarButtonDefinition<GlusterVolumeEntity>(constants.volumeProfilingAction(),
 volumeProfilingActions, CommandLocation.ContextAndToolBar));
+
+        getTable().addActionButton(new 
WebAdminMenuBarButtonDefinition<GlusterVolumeEntity>(constants.volumeProfilingAction(),
+                volumeProfilingActions,
+                CommandLocation.ContextAndToolBar));
+
+        getTable().addActionButton(new 
WebAdminMenuBarButtonDefinition<GlusterVolumeEntity>(constants.volumeSnapshotMainTabTitle(),
+                getVolumeSnapshotMenu(constants),
+                CommandLocation.ContextAndToolBar));
+    }
+
+    private List<ActionButtonDefinition<GlusterVolumeEntity>> 
getVolumeSnapshotMenu(ApplicationConstants constants) {
+        List<ActionButtonDefinition<GlusterVolumeEntity>> snapshotMenu = new 
ArrayList<ActionButtonDefinition<GlusterVolumeEntity>>();
+        WebAdminButtonDefinition<GlusterVolumeEntity> newSnapshotButton = new 
WebAdminButtonDefinition<GlusterVolumeEntity>(constants.newVolumeSnapshot()) {
+            @Override
+            protected UICommand resolveCommand() {
+                return getMainModel().getCreateSnapshotCommand();
+            }
+        };
+        snapshotMenu.add(newSnapshotButton);
+        return snapshotMenu;
     }
 
     private MenuCell<GlusterTaskSupport> 
getRebalanceActivityMenu(ApplicationConstants constants) {
diff --git 
a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/tab/gluster/SubTabGlusterVolumeSnapshotView.java
 
b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/tab/gluster/SubTabGlusterVolumeSnapshotView.java
new file mode 100644
index 0000000..79f20a5
--- /dev/null
+++ 
b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/tab/gluster/SubTabGlusterVolumeSnapshotView.java
@@ -0,0 +1,76 @@
+package org.ovirt.engine.ui.webadmin.section.main.view.tab.gluster;
+
+import 
org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeEntity;
+import 
org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeSnapshotEntity;
+import org.ovirt.engine.ui.common.idhandler.ElementIdHandler;
+import org.ovirt.engine.ui.common.uicommon.model.SearchableDetailModelProvider;
+import org.ovirt.engine.ui.common.widget.table.column.TextColumnWithTooltip;
+import 
org.ovirt.engine.ui.uicommonweb.models.gluster.GlusterVolumeSnapshotListModel;
+import org.ovirt.engine.ui.uicommonweb.models.volumes.VolumeListModel;
+import org.ovirt.engine.ui.webadmin.ApplicationConstants;
+import 
org.ovirt.engine.ui.webadmin.section.main.presenter.tab.gluster.SubTabGlusterVolumeSnapshotPresenter;
+import org.ovirt.engine.ui.webadmin.section.main.view.AbstractSubTabTableView;
+import 
org.ovirt.engine.ui.webadmin.widget.table.column.GlusterVolumeSnapshotStatusColumn;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.inject.Inject;
+
+public class SubTabGlusterVolumeSnapshotView extends 
AbstractSubTabTableView<GlusterVolumeEntity, GlusterVolumeSnapshotEntity, 
VolumeListModel, GlusterVolumeSnapshotListModel> implements 
SubTabGlusterVolumeSnapshotPresenter.ViewDef {
+
+    interface ViewIdHandler extends 
ElementIdHandler<SubTabGlusterVolumeSnapshotView> {
+        ViewIdHandler idHandler = GWT.create(ViewIdHandler.class);
+    }
+
+    @Inject
+    public 
SubTabGlusterVolumeSnapshotView(SearchableDetailModelProvider<GlusterVolumeSnapshotEntity,
 VolumeListModel, GlusterVolumeSnapshotListModel> modelProvider,
+            ApplicationConstants constants) {
+        super(modelProvider);
+        initTable(constants);
+        initWidget(getTable());
+    }
+
+    @Override
+    protected void generateIds() {
+        ViewIdHandler.idHandler.generateAndSetIds(this);
+    }
+
+    void initTable(ApplicationConstants constants) {
+        getTable().enableColumnResizing();
+
+        GlusterVolumeSnapshotStatusColumn snapshotStatusColumn = new 
GlusterVolumeSnapshotStatusColumn();
+        snapshotStatusColumn.makeSortable();
+        getTable().addColumn(snapshotStatusColumn, constants.empty(), "30px"); 
//$NON-NLS-1$
+
+        TextColumnWithTooltip<GlusterVolumeSnapshotEntity> snapshotNameColumn =
+                new TextColumnWithTooltip<GlusterVolumeSnapshotEntity>() {
+                    @Override
+                    public String getValue(GlusterVolumeSnapshotEntity 
snapshot) {
+                        return snapshot.getSnapshotName();
+                    }
+                };
+        snapshotNameColumn.makeSortable();
+        getTable().addColumn(snapshotNameColumn, 
constants.volumeSnapshotName(), "300px"); //$NON-NLS-1$
+
+        TextColumnWithTooltip<GlusterVolumeSnapshotEntity> descriptionColumn =
+                new TextColumnWithTooltip<GlusterVolumeSnapshotEntity>() {
+                    @Override
+                    public String getValue(GlusterVolumeSnapshotEntity 
snapshot) {
+                        return snapshot.getDescription();
+                    }
+                };
+        descriptionColumn.makeSortable();
+        getTable().addColumn(descriptionColumn, 
constants.volumeSnapshotDescription(), "400px"); //$NON-NLS-1$
+
+        TextColumnWithTooltip<GlusterVolumeSnapshotEntity> creationTimeColumn =
+                new TextColumnWithTooltip<GlusterVolumeSnapshotEntity>() {
+                    @Override
+                    public String getValue(GlusterVolumeSnapshotEntity 
snapshot) {
+                        DateTimeFormat df = 
DateTimeFormat.getFormat("yyyy-MM-dd, HH:mm:ss"); //$NON-NLS-1$
+                        return df.format(snapshot.getCreatedAt());
+                    }
+                };
+        creationTimeColumn.makeSortable();
+        getTable().addColumn(creationTimeColumn, 
constants.volumeSnapshotCreationTime(), "400px"); //$NON-NLS-1$
+    }
+}
diff --git 
a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/widget/table/column/GlusterVolumeSnapshotStatusCell.java
 
b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/widget/table/column/GlusterVolumeSnapshotStatusCell.java
new file mode 100644
index 0000000..1560a3c
--- /dev/null
+++ 
b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/widget/table/column/GlusterVolumeSnapshotStatusCell.java
@@ -0,0 +1,60 @@
+package org.ovirt.engine.ui.webadmin.widget.table.column;
+
+import 
org.ovirt.engine.core.common.businessentities.gluster.GlusterSnapshotStatus;
+import 
org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeSnapshotEntity;
+import org.ovirt.engine.ui.webadmin.ApplicationConstants;
+import org.ovirt.engine.ui.webadmin.ApplicationResources;
+import org.ovirt.engine.ui.webadmin.ApplicationTemplates;
+import org.ovirt.engine.ui.webadmin.gin.ClientGinjectorProvider;
+
+import com.google.gwt.cell.client.AbstractCell;
+import com.google.gwt.resources.client.ImageResource;
+import com.google.gwt.safehtml.shared.SafeHtml;
+import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
+import com.google.gwt.safehtml.shared.SafeHtmlUtils;
+import com.google.gwt.user.client.ui.AbstractImagePrototype;
+
+public class GlusterVolumeSnapshotStatusCell extends 
AbstractCell<GlusterVolumeSnapshotEntity> {
+
+    private static final ApplicationResources resources = 
ClientGinjectorProvider.getApplicationResources();
+
+    private static final ApplicationConstants constants = 
ClientGinjectorProvider.getApplicationConstants();
+
+    private static final ApplicationTemplates applicationTemplates = 
ClientGinjectorProvider.getApplicationTemplates();
+
+    @Override
+    public void render(Context context, GlusterVolumeSnapshotEntity snapshot, 
SafeHtmlBuilder sb) {
+        // Nothing to render if no snapshot is provided:
+        if (snapshot == null) {
+            return;
+        }
+
+        // Find the image corresponding to the status of the brick:
+        GlusterSnapshotStatus status = snapshot.getStatus();
+        ImageResource statusImage = null;
+        String tooltip;
+
+        switch (status) {
+        case STARTED:
+            statusImage = resources.upImage();
+            tooltip = constants.up();
+            break;
+        case STOPPED:
+            statusImage = resources.downImage();
+            tooltip = constants.down();
+            break;
+        case UNKNOWN:
+            statusImage = resources.questionMarkImage();
+            tooltip = constants.unknown();
+            break;
+        default:
+            statusImage = resources.downImage();
+            tooltip = constants.down();
+        }
+
+        // Generate the HTML for the image:
+        SafeHtml statusImageHtml =
+                
SafeHtmlUtils.fromTrustedString(AbstractImagePrototype.create(statusImage).getHTML());
+        sb.append(applicationTemplates.statusTemplate(statusImageHtml, 
tooltip));
+    }
+}
diff --git 
a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/widget/table/column/GlusterVolumeSnapshotStatusColumn.java
 
b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/widget/table/column/GlusterVolumeSnapshotStatusColumn.java
new file mode 100644
index 0000000..add4a7d
--- /dev/null
+++ 
b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/widget/table/column/GlusterVolumeSnapshotStatusColumn.java
@@ -0,0 +1,27 @@
+package org.ovirt.engine.ui.webadmin.widget.table.column;
+
+import java.util.Comparator;
+
+import 
org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeSnapshotEntity;
+import org.ovirt.engine.ui.common.widget.table.column.SortableColumn;
+
+public class GlusterVolumeSnapshotStatusColumn extends 
SortableColumn<GlusterVolumeSnapshotEntity, GlusterVolumeSnapshotEntity> {
+
+    public GlusterVolumeSnapshotStatusColumn() {
+        super(new GlusterVolumeSnapshotStatusCell());
+    }
+
+    @Override
+    public GlusterVolumeSnapshotEntity getValue(GlusterVolumeSnapshotEntity 
object) {
+        return object;
+    }
+
+    public void makeSortable() {
+        makeSortable(new Comparator<GlusterVolumeSnapshotEntity>() {
+            @Override
+            public int compare(GlusterVolumeSnapshotEntity o1, 
GlusterVolumeSnapshotEntity o2) {
+                return o1.getStatus().ordinal() - o2.getStatus().ordinal();
+            }
+        });
+    }
+}


-- 
To view, visit http://gerrit.ovirt.org/36334
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I5161753920ef72c245f1785e754df97465a19602
Gerrit-PatchSet: 1
Gerrit-Project: ovirt-engine
Gerrit-Branch: master
Gerrit-Owner: Shubhendu Tripathi <[email protected]>
_______________________________________________
Engine-patches mailing list
[email protected]
http://lists.ovirt.org/mailman/listinfo/engine-patches

Reply via email to