diff options
Diffstat (limited to 'src/com.gluster.storage.management.gui')
20 files changed, 596 insertions, 301 deletions
diff --git a/src/com.gluster.storage.management.gui/plugin.xml b/src/com.gluster.storage.management.gui/plugin.xml index 82b7f3e0..89b2460b 100644 --- a/src/com.gluster.storage.management.gui/plugin.xml +++ b/src/com.gluster.storage.management.gui/plugin.xml @@ -666,22 +666,6 @@ toolbarPath="Normal" tooltip="Create a new Volume"> </action> - <action - allowLabelUpdate="false" - class="com.gluster.storage.management.gui.actions.AddServerAction" - definitionId="com.gluster.storage.management.gui.commands.AddServer" - icon="icons/server-add.png" - id="com.gluster.storage.management.gui.actions.AddServerAction" - label="Add &Server(s)" - menubarPath="com.gluster.storage.management.gui.menu.cluster/cluster" - mode="FORCE_TEXT" - pulldown="false" - retarget="false" - state="false" - style="push" - toolbarPath="Normal" - tooltip="Add Server(s) to Cluster"> - </action> <menu id="com.gluster.storage.management.gui.menu.cluster" label="&Gluster"> @@ -711,22 +695,6 @@ toolbarPath="Normal" tooltip="Remove Server(s)"> </action> - <action - allowLabelUpdate="false" - class="com.gluster.storage.management.gui.actions.AddServerAction" - definitionId="com.gluster.storage.management.gui.commands.AddServer" - icon="icons/server-add.png" - id="com.gluster.storage.management.gui.actions.AddServerAction" - label="&Add Server(s)" - menubarPath="com.gluster.storage.management.gui.menu.servers/servers" - mode="FORCE_TEXT" - pulldown="false" - retarget="false" - state="false" - style="push" - toolbarPath="Normal" - tooltip="Add Server(s) to Cluster"> - </action> <menu id="com.gluster.storage.management.gui.menu.servers" label="&Gluster" @@ -747,7 +715,7 @@ definitionId="com.gluster.storage.management.gui.commands.RemoveServer" icon="icons/server-remove.png" id="com.gluster.storage.management.gui.actions.RemoveServerAction" - label="&Remove Server" + label="&Remove Server(s)" menubarPath="com.gluster.storage.management.gui.menu.glusterserver/glusterserver" mode="FORCE_TEXT" pulldown="false" @@ -807,7 +775,7 @@ definitionId="com.gluster.storage.management.gui.commands.AddServer" icon="icons/server-add.png" id="com.gluster.storage.management.gui.actions.AddServerAction" - label="&Add Server" + label="&Add Server(s)" menubarPath="com.gluster.storage.management.gui.menu.discoveredserver/discoveredserver" mode="FORCE_TEXT" pulldown="false" @@ -1101,7 +1069,7 @@ <action class="com.gluster.storage.management.gui.actions.RemoveServerAction" definitionId="com.gluster.storage.management.gui.commands.RemoveServer" - enablesFor="1" + enablesFor="+" icon="icons/server-remove.png" id="com.gluster.storage.management.gui.actions.RemoveServerAction" label="&Remove Server" @@ -1115,6 +1083,7 @@ allowLabelUpdate="false" class="com.gluster.storage.management.gui.actions.MigrateDiskAction" definitionId="com.gluster.storage.management.gui.commands.MigrateDisk" + enablesFor="1" icon="icons/disk-migrate.png" id="com.gluster.storage.management.gui.actions.MigrateDiskAction" label="&Migrate Disk" @@ -1131,6 +1100,7 @@ allowLabelUpdate="false" class="com.gluster.storage.management.gui.actions.DeleteVolumeAction" definitionId="com.gluster.storage.management.gui.commands.DeleteVolume" + enablesFor="1" icon="icons/volume-delete.png" id="com.gluster.storage.management.gui.actions.DeleteVolumeAction" label="&Delete Volume" @@ -1147,6 +1117,7 @@ allowLabelUpdate="false" class="com.gluster.storage.management.gui.actions.RebalanceVolumeAction" definitionId="com.gluster.storage.management.gui.commands.RebalanceVolume" + enablesFor="1" icon="icons/volume-rebalance.png" id="com.gluster.storage.management.gui.actions.RebalanceVolumeAction" label="&Rebalance Volume" @@ -1163,6 +1134,7 @@ allowLabelUpdate="false" class="com.gluster.storage.management.gui.actions.StopVolumeAction" definitionId="com.gluster.storage.management.gui.commands.StopVolume" + enablesFor="+" icon="icons/volume-stop.png" id="com.gluster.storage.management.gui.actions.StopVolumeAction" label="S&top Volume" @@ -1179,6 +1151,7 @@ allowLabelUpdate="false" class="com.gluster.storage.management.gui.actions.StartVolumeAction" definitionId="com.gluster.storage.management.gui.commands.StartVolume" + enablesFor="+" icon="icons/volume-start.png" id="com.gluster.storage.management.gui.actions.StartVolumeAction" label="&Start Volume" diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/VolumeLogTableLabelProvider.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/VolumeLogTableLabelProvider.java index 9858a25b..396d1821 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/VolumeLogTableLabelProvider.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/VolumeLogTableLabelProvider.java @@ -19,21 +19,21 @@ package com.gluster.storage.management.gui; -import com.gluster.storage.management.core.model.LogMessage; +import com.gluster.storage.management.core.model.VolumeLogMessage; import com.gluster.storage.management.core.utils.DateUtil; import com.gluster.storage.management.gui.views.details.VolumeLogsPage.LOG_TABLE_COLUMN_INDICES; public class VolumeLogTableLabelProvider extends TableLabelProviderAdapter { @Override public String getColumnText(Object element, int columnIndex) { - if (!(element instanceof LogMessage)) { + if (!(element instanceof VolumeLogMessage)) { return null; } - LogMessage logMessage = (LogMessage) element; + VolumeLogMessage logMessage = (VolumeLogMessage) element; return (columnIndex == LOG_TABLE_COLUMN_INDICES.DATE.ordinal() ? DateUtil.formatDate(logMessage.getTimestamp()) : columnIndex == LOG_TABLE_COLUMN_INDICES.TIME.ordinal() ? DateUtil.formatTime(logMessage.getTimestamp()) - : columnIndex == LOG_TABLE_COLUMN_INDICES.DISK.ordinal() ? logMessage.getDisk() + : columnIndex == LOG_TABLE_COLUMN_INDICES.BRICK.ordinal() ? logMessage.getBrickDirectory() : columnIndex == LOG_TABLE_COLUMN_INDICES.SEVERITY.ordinal() ? "" + logMessage.getSeverity() : columnIndex == LOG_TABLE_COLUMN_INDICES.MESSAGE.ordinal() ? logMessage.getMessage() : "Invalid"); } diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/AbstractActionDelegate.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/AbstractActionDelegate.java index 1c5a3c72..859d76db 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/AbstractActionDelegate.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/AbstractActionDelegate.java @@ -18,6 +18,8 @@ *******************************************************************************/ package com.gluster.storage.management.gui.actions; +import java.util.Set; + import org.eclipse.jface.action.IAction; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.viewers.ISelection; @@ -26,8 +28,10 @@ import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.IWorkbenchWindowActionDelegate; +import org.eclipse.ui.internal.UIPlugin; import com.gluster.storage.management.core.model.Entity; +import com.gluster.storage.management.gui.utils.GUIHelper; /** * All action delegates in the application should extend from this class. It provides common functionality of grabbing @@ -36,6 +40,8 @@ import com.gluster.storage.management.core.model.Entity; */ public abstract class AbstractActionDelegate implements IWorkbenchWindowActionDelegate { protected IWorkbenchWindow window; + + // the latest selected entity protected Entity selectedEntity; @Override @@ -79,6 +85,10 @@ public abstract class AbstractActionDelegate implements IWorkbenchWindowActionDe } return window.getShell(); } + + protected IWorkbenchWindow getWindow() { + return window == null ? UIPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow() : window; + } protected void showInfoDialog(final String title, final String message) { MessageDialog.openInformation(getShell(), title, message); diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/AddServerAction.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/AddServerAction.java index fa48670d..230bff6a 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/AddServerAction.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/AddServerAction.java @@ -18,33 +18,84 @@ *******************************************************************************/ package com.gluster.storage.management.gui.actions; +import java.util.HashSet; +import java.util.Set; + import org.eclipse.jface.action.IAction; import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.widgets.Display; import com.gluster.storage.management.client.GlusterDataModelManager; import com.gluster.storage.management.client.GlusterServersClient; -import com.gluster.storage.management.core.model.Entity; -import com.gluster.storage.management.core.model.EntityGroup; +import com.gluster.storage.management.core.constants.CoreConstants; import com.gluster.storage.management.core.model.Server; -import com.gluster.storage.management.core.model.Volume; +import com.gluster.storage.management.core.model.Status; import com.gluster.storage.management.core.response.GlusterServerResponse; +import com.gluster.storage.management.gui.utils.GUIHelper; public class AddServerAction extends AbstractActionDelegate { @Override - protected void performAction(IAction action) { - final String actionDesc = action.getDescription(); - GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance(); - GlusterServersClient glusterServersClient = new GlusterServersClient(); - Server server = (Server) selectedEntity; - GlusterServerResponse response = glusterServersClient.addServer(server); - if (response.getStatus().isSuccess()) { - modelManager.removeDiscoveredServer(server); - modelManager.addGlusterServer(response.getGlusterServer()); - showInfoDialog(actionDesc, "Server [" + server.getName() + "] added successfully!"); + protected void performAction(final IAction action) { + Display.getDefault().asyncExec(new Runnable() { + + @Override + public void run() { + GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance(); + GlusterServersClient glusterServersClient = new GlusterServersClient(); + + Set<Server> selectedServers = GUIHelper.getInstance().getSelectedEntities(getWindow(), Server.class); + Set<Server> successServers = new HashSet<Server>(); + Set<Server> partSuccessServers = new HashSet<Server>(); + String errMsg = ""; + String partErrMsg = ""; + for (Server server : selectedServers) { + GlusterServerResponse response = glusterServersClient.addServer(server); + Status status = response.getStatus(); + if (status.isSuccess()) { + modelManager.removeDiscoveredServer(server); + modelManager.addGlusterServer(response.getGlusterServer()); + successServers.add(server); + } else if (status.isPartSuccess()) { + modelManager.removeDiscoveredServer(server); + modelManager.addGlusterServer(response.getGlusterServer()); + partSuccessServers.add(server); + partErrMsg += "[" + server.getName() + "] : " + status; + } else { + errMsg += "[" + server.getName() + "] : " + status; + } + } + + showStatusMessage(action.getDescription(), selectedServers, successServers, errMsg, partErrMsg); + } + }); + } + + private void showStatusMessage(String dialogTitle, Set<Server> selectedServers, Set<Server> successServers, + String errMsg, String partErrMsg) { + if (successServers.size() == selectedServers.size()) { + if (selectedServers.size() == 1) { + showInfoDialog(dialogTitle, "Server [" + selectedServers.iterator().next() + "] added successfully!"); + } else { + showInfoDialog(dialogTitle, "Following servers added successfully!" + CoreConstants.NEWLINE + + selectedServers); + } + return; + } + + String finalMsg = ""; + if (successServers.size() == 0) { + finalMsg = "Server Addition Failed! Error(s):" + CoreConstants.NEWLINE + errMsg; } else { - showErrorDialog(actionDesc, "Server [" + server.getName() + " could not be added to cluster! Error: [" - + response.getStatus().getMessage() + "]"); + finalMsg = "Following servers added successfully : " + + CoreConstants.NEWLINE + + successServers + + (partErrMsg.isEmpty() ? "" : CoreConstants.NEWLINE + + "Following servers were added to cluster, but with some errors: " + CoreConstants.NEWLINE + + partErrMsg) + + (errMsg.isEmpty() ? "" : CoreConstants.NEWLINE + + "Following errors occurred on other selected servers: " + CoreConstants.NEWLINE + errMsg); } + showErrorDialog(dialogTitle, finalMsg); } @Override @@ -52,16 +103,13 @@ public class AddServerAction extends AbstractActionDelegate { System.out.println("Disposing [" + this.getClass().getSimpleName() + "]"); } - @SuppressWarnings("rawtypes") @Override public void selectionChanged(IAction action, ISelection selection) { - super.selectionChanged(action, selection); - - if (selectedEntity != null && selectedEntity instanceof Entity) { + Set<Server> selectedServers = GUIHelper.getInstance().getSelectedEntities(getWindow(), Server.class); + if (selectedServers == null || selectedServers.isEmpty()) { + action.setEnabled(false); + } else { action.setEnabled(true); - if (selectedEntity instanceof EntityGroup && ((EntityGroup) selectedEntity).getEntityType() == Volume.class) { - action.setEnabled(false); - } } } } diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/DeleteVolumeAction.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/DeleteVolumeAction.java index 41ebbca7..9222c6c7 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/DeleteVolumeAction.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/DeleteVolumeAction.java @@ -21,6 +21,7 @@ package com.gluster.storage.management.gui.actions; import org.eclipse.jface.action.IAction; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.widgets.Display; import com.gluster.storage.management.client.GlusterDataModelManager; import com.gluster.storage.management.client.VolumesClient; @@ -35,53 +36,61 @@ public class DeleteVolumeAction extends AbstractActionDelegate { private GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance(); @Override - protected void performAction(IAction action) { - final String actionDesc = action.getDescription(); + protected void performAction(final IAction action) { - String warningMessage; - if (volume.getStatus() == VOLUME_STATUS.OFFLINE) { - warningMessage = "Are you sure to delete the Volume[" + volume.getName() + "] ?"; - } else { - warningMessage = "Volume [" + volume.getName() + "] is online, \nAre you sure to continue?"; - } + Display.getDefault().asyncExec(new Runnable() { - Integer deleteOption = new MessageDialog(getShell(), "Delete Volume", GUIHelper.getInstance().getImage( - IImageKeys.VOLUME), warningMessage, MessageDialog.QUESTION, new String[] { "Cancel", - "Delete volume and data", "Delete volume, keep data" }, 2).open(); - if (deleteOption <= 0) { // By Cancel button(0) or Escape key(-1) - return; - } + @Override + public void run() { - VolumesClient client = new VolumesClient(); + final String actionDesc = action.getDescription(); - Status status; - if (volume.getStatus() == VOLUME_STATUS.ONLINE) { // To stop the volume service, if running - status = client.stopVolume(volume.getName()); - if (!status.isSuccess()) { - showErrorDialog(actionDesc, "Volume [" + volume.getName() + "] could not be stopped! Error: [" + status - + "]"); - return; - } - } - - boolean confirmDelete = false; - if (deleteOption == 1) { - confirmDelete = true; - } + String warningMessage; + if (volume.getStatus() == VOLUME_STATUS.OFFLINE) { + warningMessage = "Are you sure to delete the Volume[" + volume.getName() + "] ?"; + } else { + warningMessage = "Volume [" + volume.getName() + "] is online, \nAre you sure to continue?"; + } - status = client.deleteVolume(volume, confirmDelete); - if (status.isSuccess()) { - showInfoDialog(actionDesc, "Volume [" + volume.getName() + "] deleted successfully!"); - modelManager.deleteVolume(volume); - } else { - if (status.isPartSuccess()) { - showWarningDialog(actionDesc, "Volume deleted, but following error(s) occured: " + status); - modelManager.deleteVolume(volume); - } else { - showErrorDialog(actionDesc, - "Volume [" + volume.getName() + "] could not be deleted! Error: [" + status + "]"); + Integer deleteOption = new MessageDialog(getShell(), "Delete Volume", GUIHelper.getInstance().getImage( + IImageKeys.VOLUME), warningMessage, MessageDialog.QUESTION, new String[] { "Cancel", + "Delete volume and data", "Delete volume, keep data" }, -1).open(); + if (deleteOption <= 0) { // By Cancel button(0) or Escape key(-1) + return; + } + + VolumesClient client = new VolumesClient(); + + Status status; + if (volume.getStatus() == VOLUME_STATUS.ONLINE) { // To stop the volume service, if running + status = client.stopVolume(volume.getName()); + if (!status.isSuccess()) { + showErrorDialog(actionDesc, "Volume [" + volume.getName() + "] could not be stopped! Error: [" + + status + "]"); + return; + } + } + + boolean confirmDelete = false; + if (deleteOption == 1) { + confirmDelete = true; + } + + status = client.deleteVolume(volume, confirmDelete); + if (status.isSuccess()) { + showInfoDialog(actionDesc, "Volume [" + volume.getName() + "] deleted successfully!"); + modelManager.deleteVolume(volume); + } else { + if (status.isPartSuccess()) { + showWarningDialog(actionDesc, "Volume deleted, but following error(s) occured: " + status); + modelManager.deleteVolume(volume); + } else { + showErrorDialog(actionDesc, "Volume [" + volume.getName() + "] could not be deleted! Error: [" + + status + "]"); + } + } } - } + }); } @Override diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/RemoveDiskAction.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/RemoveDiskAction.java index 8c5d8405..ffe2469d 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/RemoveDiskAction.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/RemoveDiskAction.java @@ -30,39 +30,49 @@ public class RemoveDiskAction extends AbstractActionDelegate { boolean confirmDelete = false; @Override - protected void performAction(IAction action) { - final String actionDesc = action.getDescription(); - List<String> brickList = getBrickList(bricks); - Integer deleteOption = new MessageDialog(getShell(), "Remove Bricks(s)", GUIHelper.getInstance().getImage( - IImageKeys.VOLUME), "Are you sure you want to remove following bricks from volume [" + volume.getName() - + "] ? \n" + StringUtil.ListToString(brickList, ", "), MessageDialog.QUESTION, new String[] { "Cancel", - "Remove bricks, delete data", "Remove bricks, keep data" }, 2).open(); - if (deleteOption <= 0) { // By Cancel button(0) or Escape key(-1) - return; - } + protected void performAction(final IAction action) { + Display.getDefault().asyncExec(new Runnable() { - if (deleteOption == 1) { - confirmDelete = true; - } - BusyIndicator.showWhile(Display.getDefault(), new Runnable() { + @Override public void run() { - VolumesClient client = new VolumesClient(); - Status status = client.removeBricks(volume.getName(), bricks, confirmDelete); - - if (status.isSuccess()) { - - // Remove the bricks from the volume object - for (Brick brick : bricks) { - volume.removeBrick(brick); - } - // Update model with removed bricks in the volume - modelManager.removeBricks(volume, bricks); - - showInfoDialog(actionDesc, "Volume [" + volume.getName() + "] bricks(s) removed successfully!"); - } else { - showErrorDialog(actionDesc, "Volume [" + volume.getName() - + "] bricks(s) could not be removed! Error: [" + status + "]"); + + final String actionDesc = action.getDescription(); + List<String> brickList = getBrickList(bricks); + Integer deleteOption = new MessageDialog(getShell(), "Remove Bricks(s)", GUIHelper.getInstance() + .getImage(IImageKeys.VOLUME), "Are you sure you want to remove following bricks from volume [" + + volume.getName() + "] ? \n" + StringUtil.ListToString(brickList, ", "), + MessageDialog.QUESTION, new String[] { "Cancel", "Remove bricks, delete data", + "Remove bricks, keep data" }, -1).open(); + if (deleteOption <= 0) { // By Cancel button(0) or Escape key(-1) + return; + } + + if (deleteOption == 1) { + confirmDelete = true; } + BusyIndicator.showWhile(Display.getDefault(), new Runnable() { + public void run() { + VolumesClient client = new VolumesClient(); + Status status = client.removeBricks(volume.getName(), bricks, confirmDelete); + + if (status.isSuccess()) { + + // Remove the bricks from the volume object + for (Brick brick : bricks) { + volume.removeBrick(brick); + } + // Update model with removed bricks in the volume + modelManager.removeBricks(volume, bricks); + + showInfoDialog(actionDesc, "Volume [" + volume.getName() + + "] bricks(s) removed successfully!"); + } else { + showErrorDialog(actionDesc, "Volume [" + volume.getName() + + "] bricks(s) could not be removed! Error: [" + status + "]"); + } + } + }); + } }); diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/RemoveServerAction.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/RemoveServerAction.java index b0b863ab..0ca5627c 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/RemoveServerAction.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/RemoveServerAction.java @@ -19,57 +19,121 @@ package com.gluster.storage.management.gui.actions; import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; import org.eclipse.jface.action.IAction; import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.widgets.Display; import com.gluster.storage.management.client.GlusterDataModelManager; import com.gluster.storage.management.client.GlusterServersClient; +import com.gluster.storage.management.core.constants.CoreConstants; import com.gluster.storage.management.core.model.Cluster; import com.gluster.storage.management.core.model.GlusterServer; import com.gluster.storage.management.core.model.Status; import com.gluster.storage.management.core.model.Volume; -import com.gluster.storage.management.core.utils.StringUtil; +import com.gluster.storage.management.gui.utils.GUIHelper; public class RemoveServerAction extends AbstractActionDelegate { - - private GlusterServer server; private GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance(); @Override - protected void performAction(IAction action) { - final String actionDesc = action.getDescription(); + protected void performAction(final IAction action) { + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + final String actionDesc = action.getDescription(); - List<String> configuredVolumes = getServerVolumeNames(server.getName()); + Set<GlusterServer> selectedServers = GUIHelper.getInstance().getSelectedEntities(getWindow(), + GlusterServer.class); - if (configuredVolumes.size() > 0) { - String volumes = StringUtil.ListToString(configuredVolumes, ", "); - showErrorDialog(actionDesc, "Server cannot be removed as it is being used by following volumes: [" - + volumes + "]"); - return; - } + if (!validate(action, selectedServers)) { + return; + } + + boolean confirmed = showConfirmDialog(actionDesc, "Are you sure you want to remove the server(s) " + + selectedServers + " ?"); + if (!confirmed) { + return; + } - boolean confirmed = showConfirmDialog(actionDesc, - "Are you sure you want to remove this server [" + server.getName() + "] ?"); - if (!confirmed) { + Set<GlusterServer> successServers = new HashSet<GlusterServer>(); + String errMsg = ""; + for (GlusterServer server : selectedServers) { + GlusterServersClient client = new GlusterServersClient(); + Status status = client.removeServer(server.getName()); + if (status.isSuccess()) { + GlusterServer glusterServer = (GlusterServer) server; + modelManager.removeGlusterServer(glusterServer); + successServers.add(server); + } else { + errMsg += "[" + server.getName() + "] : " + status; + } + } + + showStatusMessage(action.getDescription(), selectedServers, successServers, errMsg); + } + }); + } + + private void showStatusMessage(String dialogTitle, Set<GlusterServer> selectedServers, Set<GlusterServer> successServers, + String errMsg) { + if (successServers.size() == selectedServers.size()) { + if(selectedServers.size() == 1) { + showInfoDialog(dialogTitle, "Server [" + selectedServers.iterator().next() + "] removed successfully!"); + } else { + showInfoDialog(dialogTitle, "Following servers removed successfully: " + CoreConstants.NEWLINE + + selectedServers); + } return; } + + if (successServers.size() == 0) { + errMsg = "Server Removal Failed! Error(s):" + CoreConstants.NEWLINE + errMsg; + } else { + errMsg = "Following servers removed successfully : " + CoreConstants.NEWLINE + successServers + + CoreConstants.NEWLINE + "Following errors occurred on other selected servers: " + + CoreConstants.NEWLINE + errMsg; + } + showErrorDialog(dialogTitle, errMsg); + } - GlusterServersClient client = new GlusterServersClient(); - Status status = client.removeServer(server.getName()); + private boolean validate(IAction action, Set<GlusterServer> selectedServers) { + Map<GlusterServer, List<String>> usedServers = new HashMap<GlusterServer, List<String>>(); + for (GlusterServer server : selectedServers) { + List<String> configuredVolumes = getServerVolumeNames(server.getName()); - if (status.isSuccess()) { - showInfoDialog(actionDesc, "Server removed successfully"); - GlusterServer glusterServer = (GlusterServer) server; - GlusterDataModelManager.getInstance().removeGlusterServer(glusterServer); - } else { - showErrorDialog(actionDesc, "Server could not be removed. Error: [" + status + "]"); + if (configuredVolumes.size() > 0) { + usedServers.put(server, configuredVolumes); + } + } + + if (usedServers.size() > 0) { + if (usedServers.size() == 1) { + showErrorDialog(action.getDescription(), "Server [" + usedServers.keySet().iterator().next() + + "] cannot be removed as it is being used by volume(s): " + CoreConstants.NEWLINE + + usedServers.values().iterator().next() + "]"); + } else { + String serverList = ""; + for (Entry<GlusterServer, List<String>> entry : usedServers.entrySet()) { + serverList += entry.getKey() + " -> " + entry.getValue() + CoreConstants.NEWLINE; + } + showErrorDialog(action.getDescription(), + "Following servers cannot be removed as they are being used by volume(s): " + + CoreConstants.NEWLINE + serverList + "]"); + } + return false; } + return true; } private List<String> getServerVolumeNames(String serverName) { - Cluster cluster = GlusterDataModelManager.getInstance().getModel().getCluster(); + Cluster cluster = modelManager.getModel().getCluster(); List<String> volumeNames = new ArrayList<String>(); for (Volume volume : cluster.getVolumes()) { for (String brick : volume.getDisks()) { @@ -82,16 +146,17 @@ public class RemoveServerAction extends AbstractActionDelegate { return volumeNames; } - @Override public void dispose() { - System.out.println("Disposing [" + this.getClass().getSimpleName() + "]"); } - + @Override public void selectionChanged(IAction action, ISelection selection) { - super.selectionChanged(action, selection); - if (selectedEntity instanceof GlusterServer) { - server = (GlusterServer) selectedEntity; + Set<GlusterServer> selectedServers = GUIHelper.getInstance().getSelectedEntities(getWindow(), + GlusterServer.class); + if(selectedServers == null || selectedServers.isEmpty()) { + action.setEnabled(false); + } else { + action.setEnabled(true); } } } diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/ResetVolumeOptionsAction.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/ResetVolumeOptionsAction.java index 5182d25f..f23f3b15 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/ResetVolumeOptionsAction.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/ResetVolumeOptionsAction.java @@ -2,6 +2,7 @@ package com.gluster.storage.management.gui.actions; import org.eclipse.jface.action.IAction; import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.IWorkbenchWindowActionDelegate; @@ -10,6 +11,7 @@ import com.gluster.storage.management.client.VolumesClient; import com.gluster.storage.management.core.model.Status; import com.gluster.storage.management.core.model.Volume; import com.gluster.storage.management.core.model.Volume.VOLUME_STATUS; +import com.gluster.storage.management.gui.utils.GUIHelper; public class ResetVolumeOptionsAction extends AbstractActionDelegate { private Volume volume; @@ -22,23 +24,29 @@ public class ResetVolumeOptionsAction extends AbstractActionDelegate { } @Override - protected void performAction(IAction action) { - final String actionDesc = action.getDescription(); + protected void performAction(final IAction action) { + Display.getDefault().asyncExec(new Runnable() { - boolean confirmed = showConfirmDialog(actionDesc, - "Are you sure you want to reset all options of the volume [" + volume.getName() + "] ?"); - if (!confirmed) { - return; - } + @Override + public void run() { + final String actionDesc = action.getDescription(); - final Status status = resetVolumeOptions(); - if (status.isSuccess()) { - showInfoDialog(actionDesc, "Volume options for [" + volume.getName() + "] reset successfully!"); - modelManager.resetVolumeOptions(volume); - } else { - showErrorDialog(actionDesc, "Volume options for [" + volume.getName() + "] could not be reset! Error: [" + status - + "]"); - } + boolean confirmed = showConfirmDialog(actionDesc, + "Are you sure you want to reset all options of the volume [" + volume.getName() + "] ?"); + if (!confirmed) { + return; + } + + final Status status = resetVolumeOptions(); + if (status.isSuccess()) { + showInfoDialog(actionDesc, "Volume options for [" + volume.getName() + "] reset successfully!"); + modelManager.resetVolumeOptions(volume); + } else { + showErrorDialog(actionDesc, "Volume options for [" + volume.getName() + + "] could not be reset! Error: [" + status + "]"); + } + } + }); } private Status resetVolumeOptions() { @@ -54,11 +62,12 @@ public class ResetVolumeOptionsAction extends AbstractActionDelegate { */ @Override public void selectionChanged(IAction action, ISelection selection) { - super.selectionChanged(action, selection); - - if (selectedEntity instanceof Volume) { - volume = (Volume) selectedEntity; + volume = GUIHelper.getInstance().getSelectedEntity(getWindow(), Volume.class); + + if (volume instanceof Volume) { action.setEnabled(volume.getOptions().size() > 0); + } else { + action.setEnabled(false); } } } diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/StopVolumeAction.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/StopVolumeAction.java index 33d12ce3..68623aaf 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/StopVolumeAction.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/StopVolumeAction.java @@ -19,40 +19,52 @@ package com.gluster.storage.management.gui.actions; import org.eclipse.jface.action.IAction; +import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.widgets.Display; import com.gluster.storage.management.client.GlusterDataModelManager; import com.gluster.storage.management.client.VolumesClient; import com.gluster.storage.management.core.model.Status; import com.gluster.storage.management.core.model.Volume; import com.gluster.storage.management.core.model.Volume.VOLUME_STATUS; +import com.gluster.storage.management.gui.IImageKeys; +import com.gluster.storage.management.gui.utils.GUIHelper; public class StopVolumeAction extends AbstractActionDelegate { private Volume volume; private GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance(); @Override - protected void performAction(IAction action) { - final String actionDesc = action.getDescription(); - if (volume.getStatus() == VOLUME_STATUS.OFFLINE) { - showWarningDialog(actionDesc, "Volume [" + volume.getName() + "] is already offline!"); - return; // Volume already offline. Don't do anything. - } + protected void performAction(final IAction action) { + Display.getDefault().asyncExec(new Runnable() { - boolean confirmed = showConfirmDialog(actionDesc, - "Are you sure you want to stop the volume [" + volume.getName() + "] ?"); - if (!confirmed) { - return; - } + @Override + public void run() { + final String actionDesc = action.getDescription(); + if (volume.getStatus() == VOLUME_STATUS.OFFLINE) { + showWarningDialog(actionDesc, "Volume [" + volume.getName() + "] is already offline!"); + return; // Volume already offline. Don't do anything. + } - final Status status = stopVolume(); - if (status.isSuccess()) { - showInfoDialog(actionDesc, "Volume [" + volume.getName() + "] stopped successfully!"); - modelManager.updateVolumeStatus(volume, VOLUME_STATUS.OFFLINE); - } else { - showErrorDialog(actionDesc, "Volume [" + volume.getName() + "] could not be stopped! Error: [" + status - + "]"); - } + Integer deleteOption = new MessageDialog(getShell(), "Stop Volume", GUIHelper.getInstance().getImage( + IImageKeys.VOLUME), "Are you sure you want to stop the volume [" + volume.getName() + "] ?", + MessageDialog.QUESTION, new String[] { "No", "Yes" }, -1).open(); + + if (deleteOption <= 0) { + return; + } + + final Status status = stopVolume(); + if (status.isSuccess()) { + showInfoDialog(actionDesc, "Volume [" + volume.getName() + "] stopped successfully!"); + modelManager.updateVolumeStatus(volume, VOLUME_STATUS.OFFLINE); + } else { + showErrorDialog(actionDesc, "Volume [" + volume.getName() + "] could not be stopped! Error: [" + + status + "]"); + } + } + }); } private Status stopVolume() { diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/CreateVolumePage1.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/CreateVolumePage1.java index d46c71d8..e7f46a66 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/CreateVolumePage1.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/CreateVolumePage1.java @@ -213,7 +213,7 @@ public class CreateVolumePage1 extends WizardPage { private void createDisksLabel(Composite container) { Label lblDisks = new Label(container, SWT.RIGHT); lblDisks.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); - lblDisks.setText("Disks: "); + lblDisks.setText("Bricks: "); } private void createTransportTypeValueLabel(Composite container) { @@ -340,15 +340,15 @@ public class CreateVolumePage1 extends WizardPage { int diskCount = selectedDisks.size(); if(diskCount < 1) { - setError("At least one disk must be selected!"); + setError("At least one brick must be selected!"); } VOLUME_TYPE volumeType = (VOLUME_TYPE) ((IStructuredSelection) typeComboViewer .getSelection()).getFirstElement(); if (volumeType == VOLUME_TYPE.DISTRIBUTED_MIRROR && diskCount % 2 != 0) { - setError("Mirror type volume requires disks in multiples of two"); + setError("Mirror type volume requires bricks in multiples of two"); } else if (volumeType == VOLUME_TYPE.DISTRIBUTED_STRIPE && diskCount % 4 != 0) { - setError("Stripe type volume requires disks in multiples of four"); + setError("Stripe type volume requires bricks in multiples of four"); } } diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/LoginDialog.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/LoginDialog.java index d480e503..9db0f0e8 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/LoginDialog.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/LoginDialog.java @@ -200,7 +200,8 @@ public class LoginDialog extends Dialog { String password = connectionDetails.getPassword(); UsersClient usersClient = new UsersClient(); - if (usersClient.authenticate(user, password).isSuccess()) { + Status loginStatus = usersClient.authenticate(user, password); + if (loginStatus.isSuccess()) { close(); ClustersClient clustersClient = new ClustersClient(usersClient.getSecurityToken()); List<String> clusterNames = getClusterNames(clustersClient); @@ -250,7 +251,7 @@ public class LoginDialog extends Dialog { close(); } } else { - MessageDialog.openError(getShell(), "Authentication Failed", "Invalid User ID or password"); + MessageDialog.openError(getShell(), "Authentication Failed", loginStatus.getMessage()); } } diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/GUIHelper.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/GUIHelper.java index 09bd40d6..a38c6b38 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/GUIHelper.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/GUIHelper.java @@ -18,7 +18,11 @@ *******************************************************************************/ package com.gluster.storage.management.gui.utils; +import java.util.Arrays; +import java.util.HashSet; import java.util.Iterator; +import java.util.List; +import java.util.Set; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IAction; @@ -28,11 +32,17 @@ import org.eclipse.jface.fieldassist.ControlDecoration; import org.eclipse.jface.fieldassist.FieldDecorationRegistry; import org.eclipse.jface.layout.TableColumnLayout; import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.viewers.CheckStateChangedEvent; +import org.eclipse.jface.viewers.CheckboxTableViewer; import org.eclipse.jface.viewers.ColumnLabelProvider; import org.eclipse.jface.viewers.ColumnLayoutData; import org.eclipse.jface.viewers.ColumnWeightData; +import org.eclipse.jface.viewers.ICheckStateListener; import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.StructuredViewer; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TableViewerColumn; @@ -70,6 +80,7 @@ import org.eclipse.ui.progress.IProgressConstants; import com.gluster.storage.management.core.exceptions.GlusterRuntimeException; import com.gluster.storage.management.core.model.Disk; +import com.gluster.storage.management.core.utils.JavaUtil; import com.gluster.storage.management.gui.Application; import com.gluster.storage.management.gui.IImageKeys; import com.gluster.storage.management.gui.views.NavigationView; @@ -355,24 +366,79 @@ public class GUIHelper { * Type of the selected object to look for * @return The selected object of given type if found, else null */ + @SuppressWarnings("rawtypes") public Object getSelectedEntity(IWorkbenchSite site, Class expectedType) { return getSelectedEntity(site.getWorkbenchWindow(), expectedType); } - public Object getSelectedEntity(IWorkbenchWindow window, Class expectedType) { + @SuppressWarnings({ "unchecked", "rawtypes" }) + public <T> T getSelectedEntity(IWorkbenchWindow window, Class<T> expectedType) { ISelection selection = window.getSelectionService().getSelection(NavigationView.ID); if (selection instanceof IStructuredSelection) { Iterator<Object> iter = ((IStructuredSelection) selection).iterator(); while (iter.hasNext()) { Object selectedObj = iter.next(); if (selectedObj.getClass() == expectedType) { - return selectedObj; + return (T)selectedObj; } } } return null; } + + /** + * Fetches the currently selected objects from the workbench site and returns those of given type. If none of the + * selected objects are of given type, returns null + * + * @param site + * The workbench site + * @param expectedType + * Type of the selected objects to look for + * @return The selected objects of given type if found, else null + */ + public <T> Set<T> getSelectedEntities(IWorkbenchSite site, Class<T> expectedType) { + return getSelectedEntities(site.getWorkbenchWindow(), expectedType); + } + @SuppressWarnings("unchecked") + public <T> Set<T> getSelectedEntities(IWorkbenchWindow window, Class<T> expectedType) { + Set<T> selectedEntities = new HashSet<T>(); + ISelection selection = window.getSelectionService().getSelection(); + if (selection instanceof IStructuredSelection) { + Iterator<Object> iter = ((IStructuredSelection) selection).iterator(); + while (iter.hasNext()) { + Object selectedObj = iter.next(); + if (selectedObj.getClass() == expectedType) { + selectedEntities.add((T) selectedObj); + } + } + } + return selectedEntities; + } + + public void configureCheckboxTableViewer(final CheckboxTableViewer tableViewer) { + tableViewer.addCheckStateListener(new ICheckStateListener() { + + @Override + public void checkStateChanged(CheckStateChangedEvent event) { + tableViewer.setSelection(new StructuredSelection(tableViewer.getCheckedElements())); + } + }); + + tableViewer.addSelectionChangedListener(new ISelectionChangedListener() { + + @SuppressWarnings("unchecked") + @Override + public void selectionChanged(SelectionChangedEvent event) { + List<Object> checkedElements = Arrays.asList(tableViewer.getCheckedElements()); + List<Object> selectedElements = ((IStructuredSelection)event.getSelection()).toList(); + + if (JavaUtil.listsDiffer(checkedElements, selectedElements)) { + tableViewer.setSelection(new StructuredSelection(tableViewer.getCheckedElements())); + } + } + }); + } public void showProgressView() { try { diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/ClusterSummaryView.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/ClusterSummaryView.java index da9d6544..cc5c2b63 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/ClusterSummaryView.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/ClusterSummaryView.java @@ -184,7 +184,7 @@ public class ClusterSummaryView extends ViewPart { CLabel lblAlert = new CLabel(section, SWT.FLAT); Image alertImage = null; switch (alert.getType()) { - case OFFLINE_VOLUME_DISKS_ALERT: + case OFFLINE_VOLUME_BRICKS_ALERT: alertImage = guiHelper.getImage(IImageKeys.DISK_OFFLINE); break; case DISK_USAGE_ALERT: @@ -293,7 +293,7 @@ public class ClusterSummaryView extends ViewPart { case DISK_FORMAT: taskImage = guiHelper.getImage(IImageKeys.DISK); break; - case DISK_MIGRATE: + case BRICK_MIGRATE: taskImage = guiHelper.getImage(IImageKeys.DISK_MIGRATE); break; case VOLUME_REBALANCE: diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServersView.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServersView.java index 06b1e282..fa9c2e7f 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServersView.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServersView.java @@ -52,7 +52,7 @@ public class GlusterServersView extends ViewPart implements IDoubleClickListener servers = (EntityGroup<GlusterServer>)guiHelper.getSelectedEntity(getSite(), EntityGroup.class); } - page = new GlusterServersPage(parent, SWT.NONE, servers); + page = new GlusterServersPage(getSite(), parent, SWT.NONE, servers); page.addDoubleClickListener(this); } diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumeSummaryView.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumeSummaryView.java index 11717ee7..2d9b8700 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumeSummaryView.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumeSummaryView.java @@ -127,7 +127,7 @@ public class VolumeSummaryView extends ViewPart { List<Alert> alerts = GlusterDataModelManager.getInstance().getModel().getCluster().getAlerts(); for (int i = 0; i < alerts.size(); i++) { - if (alerts.get(i).getType() == Alert.ALERT_TYPES.OFFLINE_VOLUME_DISKS_ALERT + if (alerts.get(i).getType() == Alert.ALERT_TYPES.OFFLINE_VOLUME_BRICKS_ALERT && alerts.get(i).getReference().split(":")[0].trim().equals(volume.getName())) { addAlertLabel(section, alerts.get(i)); } diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumesSummaryView.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumesSummaryView.java index 7909f155..990e569c 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumesSummaryView.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumesSummaryView.java @@ -96,7 +96,7 @@ public class VolumesSummaryView extends ViewPart { } private void addAlertLabel(Composite section, Alert alert) { - if (alert.getType() == Alert.ALERT_TYPES.OFFLINE_VOLUME_DISKS_ALERT) { + if (alert.getType() == Alert.ALERT_TYPES.OFFLINE_VOLUME_BRICKS_ALERT) { CLabel lblAlert = new CLabel(section, SWT.NONE); lblAlert.setImage((alert.getType() == Alert.ALERT_TYPES.DISK_USAGE_ALERT) ? guiHelper .getImage(IImageKeys.LOW_DISK_SPACE) : guiHelper.getImage(IImageKeys.DISK_OFFLINE)); @@ -118,14 +118,14 @@ public class VolumesSummaryView extends ViewPart { private void addRunningTaskLabel(Composite section, RunningTask task) { // Task related to Volumes context - if (task.getType() == RunningTask.TASK_TYPES.DISK_MIGRATE + if (task.getType() == RunningTask.TASK_TYPES.BRICK_MIGRATE || task.getType() == RunningTask.TASK_TYPES.VOLUME_REBALANCE) { if (task.getStatus().isPercentageSupported()) { // TODO Progress bar } CLabel lblAlert = new CLabel(section, SWT.NONE); lblAlert.setText(task.getTaskInfo()); - lblAlert.setImage((task.getType() == RunningTask.TASK_TYPES.DISK_MIGRATE) ? guiHelper + lblAlert.setImage((task.getType() == RunningTask.TASK_TYPES.BRICK_MIGRATE) ? guiHelper .getImage(IImageKeys.DISK_MIGRATE) : guiHelper.getImage(IImageKeys.VOLUME_REBALANCE)); lblAlert.redraw(); } diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/GlusterServersPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/GlusterServersPage.java index ef104fe2..36f60998 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/GlusterServersPage.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/GlusterServersPage.java @@ -22,7 +22,6 @@ import org.eclipse.jface.layout.TableColumnLayout; import org.eclipse.jface.viewers.CheckboxTableViewer; import org.eclipse.jface.viewers.ColumnWeightData; import org.eclipse.jface.viewers.IDoubleClickListener; -import org.eclipse.jface.viewers.TableViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; @@ -36,9 +35,14 @@ import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.IWorkbenchSite; import org.eclipse.ui.forms.widgets.FormToolkit; +import com.gluster.storage.management.client.GlusterDataModelManager; +import com.gluster.storage.management.core.model.ClusterListener; +import com.gluster.storage.management.core.model.DefaultClusterListener; import com.gluster.storage.management.core.model.EntityGroup; +import com.gluster.storage.management.core.model.Event; import com.gluster.storage.management.core.model.GlusterServer; import com.gluster.storage.management.gui.EntityGroupContentProvider; import com.gluster.storage.management.gui.GlusterServerTableLabelProvider; @@ -47,7 +51,7 @@ import com.gluster.storage.management.gui.utils.GUIHelper; public class GlusterServersPage extends Composite { private final FormToolkit toolkit = new FormToolkit(Display.getCurrent()); - private TableViewer tableViewer; + private CheckboxTableViewer tableViewer; private GUIHelper guiHelper = GUIHelper.getInstance(); public enum GLUSTER_SERVER_TABLE_COLUMN_INDICES { @@ -57,28 +61,23 @@ public class GlusterServersPage extends Composite { private static final String[] GLUSTER_SERVER_TABLE_COLUMN_NAMES = new String[] { "Name", "IP Address(es)", "Number\nof CPUs", "Total\nMemory (GB)", "Space (GB)", "Space\nAvailable (GB)", "Status" }; // Removed "Preferred\nNetwork", - public GlusterServersPage(Composite parent, int style) { + public GlusterServersPage(IWorkbenchSite site, final Composite parent, int style, EntityGroup<GlusterServer> servers) { super(parent, style); - addDisposeListener(new DisposeListener() { - public void widgetDisposed(DisposeEvent e) { - toolkit.dispose(); - } - }); toolkit.adapt(this); toolkit.paintBordersFor(this); setupPageLayout(); Text filterText = guiHelper.createFilterText(toolkit, this); - setupServerTableViewer(filterText); - } - - public GlusterServersPage(final Composite parent, int style, EntityGroup<GlusterServer> servers) { - this(parent, style); + setupServerTableViewer(site, filterText); tableViewer.setInput(servers); parent.layout(); // Important - this actually paints the table + createListeners(parent); + } + + private void createListeners(final Composite parent) { /** * Ideally not required. However the table viewer is not getting laid out properly on performing * "maximize + restore" So this is a hack to make sure that the table is laid out again on re-size of the window @@ -90,6 +89,34 @@ public class GlusterServersPage extends Composite { parent.layout(); } }); + + final ClusterListener clusterListener = new DefaultClusterListener() { + + @Override + public void serverAdded(GlusterServer server) { + tableViewer.refresh(); + } + + @Override + public void serverRemoved(GlusterServer server) { + tableViewer.refresh(); + } + + @Override + public void serverChanged(GlusterServer server, Event event) { + tableViewer.update(server, null); + } + }; + + final GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance(); + modelManager.addClusterListener(clusterListener); + + addDisposeListener(new DisposeListener() { + public void widgetDisposed(DisposeEvent e) { + toolkit.dispose(); + modelManager.removeClusterListener(clusterListener); + } + }); } public void addDoubleClickListener(IDoubleClickListener listener) { @@ -122,8 +149,8 @@ public class GlusterServersPage extends Composite { //setColumnProperties(table, SERVER_DISK_TABLE_COLUMN_INDICES.DISK_SPACE_IN_USE, SWT.CENTER, 90); } - private TableViewer createServerTableViewer(Composite parent) { - TableViewer tableViewer = CheckboxTableViewer.newCheckList(parent, SWT.FLAT | SWT.FULL_SELECTION | SWT.MULTI); + private CheckboxTableViewer createServerTableViewer(Composite parent) { + CheckboxTableViewer tableViewer = CheckboxTableViewer.newCheckList(parent, SWT.FLAT | SWT.FULL_SELECTION | SWT.MULTI); //TableViewer tableViewer = new TableViewer(parent, SWT.FLAT | SWT.FULL_SELECTION | SWT.MULTI); tableViewer.setLabelProvider(new GlusterServerTableLabelProvider()); tableViewer.setContentProvider(new EntityGroupContentProvider<GlusterServer>()); @@ -140,9 +167,14 @@ public class GlusterServersPage extends Composite { return tableViewerComposite; } - private void setupServerTableViewer(final Text filterText) { + private void setupServerTableViewer(IWorkbenchSite site, final Text filterText) { Composite tableViewerComposite = createTableViewerComposite(); tableViewer = createServerTableViewer(tableViewerComposite); + site.setSelectionProvider(tableViewer); + + // make sure that table selection is driven by checkbox selection + guiHelper.configureCheckboxTableViewer(tableViewer); + // Create a case insensitive filter for the table viewer using the filter text field guiHelper.createFilter(tableViewer, filterText, false); } diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/VolumeLogsPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/VolumeLogsPage.java index 811b4c5c..9eb7357e 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/VolumeLogsPage.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/VolumeLogsPage.java @@ -51,7 +51,7 @@ import com.gluster.storage.management.client.VolumesClient; import com.gluster.storage.management.core.constants.CoreConstants; import com.gluster.storage.management.core.constants.GlusterConstants; import com.gluster.storage.management.core.constants.GlusterConstants.VOLUME_LOG_LEVELS; -import com.gluster.storage.management.core.model.LogMessage; +import com.gluster.storage.management.core.model.VolumeLogMessage; import com.gluster.storage.management.core.model.Status; import com.gluster.storage.management.core.model.Volume; import com.gluster.storage.management.core.response.LogMessageListResponse; @@ -68,12 +68,12 @@ public class VolumeLogsPage extends Composite { private Volume volume; public enum LOG_TABLE_COLUMN_INDICES { - DATE, TIME, DISK, SEVERITY, MESSAGE + DATE, TIME, BRICK, SEVERITY, MESSAGE }; - private static final String[] LOG_TABLE_COLUMN_NAMES = new String[] { "Date", "Time", "Disk", "Severity", "Message" }; + private static final String[] LOG_TABLE_COLUMN_NAMES = new String[] { "Date", "Time", "Brick", "Severity", "Message" }; private TableViewer tableViewer; - private Combo disksCombo; + private Combo bricksCombo; private Combo severityCombo; private DateTime fromDate; private DateTime fromTime; @@ -110,8 +110,8 @@ public class VolumeLogsPage extends Composite { createLineCountLabel(composite); createLineCountText(composite); - createDiskLabel(composite); - createDisksCombo(composite); + createBricksLabel(composite); + createBricksCombo(composite); createSeverityLabel(composite); createSeverityCombo(composite); @@ -185,12 +185,12 @@ public class VolumeLogsPage extends Composite { return; } - LogMessageListResponse response = client.getLogs(volume.getName(), disksCombo.getText(), + LogMessageListResponse response = client.getLogs(volume.getName(), bricksCombo.getText(), severityCombo.getText(), fromTimestamp, toTimestamp, Integer.parseInt(lineCountText.getText())); Status status = response.getStatus(); if (status.isSuccess()) { - List<LogMessage> logMessages = response.getLogMessages(); - tableViewer.setInput(logMessages.toArray(new LogMessage[0])); + List<VolumeLogMessage> logMessages = response.getLogMessages(); + tableViewer.setInput(logMessages.toArray(new VolumeLogMessage[0])); tableViewer.refresh(); } else { MessageDialog.openError(getShell(), "Volume Logs", "Error while fetching volume logs: [" + status @@ -321,17 +321,17 @@ public class VolumeLogsPage extends Composite { lblSeverity.setBounds(480, 15, 70, 20); } - private void createDisksCombo(Composite composite) { - disksCombo = new Combo(composite, SWT.READ_ONLY); - disksCombo.setBounds(365, 15, 100, 20); - disksCombo.setItems( volume.getBrickDirectories().toArray(new String[0])); - disksCombo.add(CoreConstants.ALL, 0); - toolkit.adapt(disksCombo); - toolkit.paintBordersFor(disksCombo); - disksCombo.select(0); + private void createBricksCombo(Composite composite) { + bricksCombo = new Combo(composite, SWT.READ_ONLY); + bricksCombo.setBounds(365, 15, 100, 20); + bricksCombo.setItems( volume.getBrickDirectories().toArray(new String[0])); + bricksCombo.add(CoreConstants.ALL, 0); + toolkit.adapt(bricksCombo); + toolkit.paintBordersFor(bricksCombo); + bricksCombo.select(0); } - private void createDiskLabel(Composite composite) { + private void createBricksLabel(Composite composite) { Label lblMessagesAndFilter = toolkit.createLabel(composite, "messages, and filter on bricks", SWT.NONE); lblMessagesAndFilter.setBounds(160, 15, 200, 20); } @@ -373,7 +373,7 @@ public class VolumeLogsPage extends Composite { setColumnProperties(table, LOG_TABLE_COLUMN_INDICES.DATE, SWT.CENTER, 50); setColumnProperties(table, LOG_TABLE_COLUMN_INDICES.TIME, SWT.CENTER, 50); - setColumnProperties(table, LOG_TABLE_COLUMN_INDICES.DISK, SWT.CENTER, 50); + setColumnProperties(table, LOG_TABLE_COLUMN_INDICES.BRICK, SWT.CENTER, 50); setColumnProperties(table, LOG_TABLE_COLUMN_INDICES.SEVERITY, SWT.CENTER, 50); setColumnProperties(table, LOG_TABLE_COLUMN_INDICES.MESSAGE, SWT.LEFT, 100); } diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/VolumeOptionsPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/VolumeOptionsPage.java index 3e8e8baa..22d38e50 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/VolumeOptionsPage.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/VolumeOptionsPage.java @@ -18,6 +18,7 @@ *******************************************************************************/ package com.gluster.storage.management.gui.views.details; +import java.util.List; import java.util.Map.Entry; import org.apache.commons.lang.WordUtils; @@ -68,19 +69,22 @@ public class VolumeOptionsPage extends Composite { private Volume volume; private DefaultClusterListener clusterListener; private Text filterText; + private List<VolumeOptionInfo> defaultVolumeOptions = GlusterDataModelManager.getInstance() + .getVolumeOptionsDefaults(); public enum OPTIONS_TABLE_COLUMN_INDICES { OPTION_KEY, OPTION_VALUE }; private static final String[] OPTIONS_TABLE_COLUMN_NAMES = new String[] { "Option Key", "Option Value" }; - private Button addButton; + private Button addTopButton; + private Button addBottomButton; private TableViewerColumn keyColumn; private OptionKeyEditingSupport keyEditingSupport; public VolumeOptionsPage(final Composite parent, int style, Volume volume) { super(parent, style); - + this.volume = volume; toolkit.adapt(this); @@ -88,61 +92,76 @@ public class VolumeOptionsPage extends Composite { setupPageLayout(); filterText = guiHelper.createFilterText(toolkit, this); - createAddButton(); + + addTopButton = createAddButton(); setupOptionsTableViewer(filterText); - - createAddButton(); + + addBottomButton = createAddButton(); + + if (defaultVolumeOptions.size() == volume.getOptions().size()) { + setAddButtonsEnabled(false); + } tableViewer.setInput(volume.getOptions().entrySet()); - + parent.layout(); // Important - this actually paints the table registerListeners(parent); } - private void createAddButton() { - addButton = toolkit.createButton(this, "&Add", SWT.FLAT); - addButton.addSelectionListener(new SelectionAdapter() { + private void setAddButtonsEnabled(boolean enable) { + addTopButton.setEnabled(enable); + addBottomButton.setEnabled(enable); + } + + private Button createAddButton() { + Button button = toolkit.createButton(this, "&Add", SWT.FLAT); + button.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { // add an empty option to be filled up by user volume.setOption("", ""); - + tableViewer.refresh(); tableViewer.setSelection(new StructuredSelection(getEntry(""))); - keyColumn.getViewer().editElement(getEntry(""), 0); // edit newly created entry - + keyColumn.getViewer().editElement(getEntry(""), 0); // edit newly created entry + // disable the add button AND search filter textbox till user fills up the new option - addButton.setEnabled(false); + setAddButtonsEnabled(false); filterText.setEnabled(false); } private Entry<String, String> getEntry(String key) { - for(Entry<String, String> entry : volume.getOptions().entrySet()) { - if(entry.getKey().equals(key)) { + for (Entry<String, String> entry : volume.getOptions().entrySet()) { + if (entry.getKey().equals(key)) { return entry; } } return null; } }); - + // Make sure that add button is enabled only when search filter textbox is empty filterText.addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent e) { - if(filterText.getText().length() > 0) { - addButton.setEnabled(false); + if (filterText.getText().length() > 0) { + setAddButtonsEnabled(false); } else { - addButton.setEnabled(true); + if (defaultVolumeOptions.size() == volume.getOptions().size()) { + setAddButtonsEnabled(false); + } else { + setAddButtonsEnabled(true); + } } } }); + return button; } private void registerListeners(final Composite parent) { addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { - if(!addButton.isEnabled()) { + if (!(addTopButton.isEnabled() || addBottomButton.isEnabled())) { // user has selected key, but not added value. Since this is not a valid entry, // remove the last option (without value) from the volume volume.getOptions().remove(keyEditingSupport.getEntryBeingAdded().getKey()); @@ -164,12 +183,12 @@ public class VolumeOptionsPage extends Composite { parent.layout(); } }); - + parent.addDisposeListener(new DisposeListener() { - + @Override public void widgetDisposed(DisposeEvent e) { - if(!addButton.isEnabled()) { + if (!(addTopButton.isEnabled() || addBottomButton.isEnabled())) { // user has selected key, but not added value. Since this is not a valid entry, // remove the last option (without value) from the volume Entry<String, String> entryBeingAdded = keyEditingSupport.getEntryBeingAdded(); @@ -178,27 +197,32 @@ public class VolumeOptionsPage extends Composite { } }); - clusterListener = new DefaultClusterListener() { @SuppressWarnings("unchecked") @Override public void volumeChanged(Volume volume, Event event) { super.volumeChanged(volume, event); - if(event.getEventType() == EVENT_TYPE.VOLUME_OPTIONS_RESET) { - if(!tableViewer.getControl().isDisposed()) { + if (event.getEventType() == EVENT_TYPE.VOLUME_OPTIONS_RESET) { + if (!tableViewer.getControl().isDisposed()) { tableViewer.refresh(); + setAddButtonsEnabled(true); } } - - if(event.getEventType() == EVENT_TYPE.VOLUME_OPTION_SET) { - Entry<String, String> eventEntry = (Entry<String, String>)event.getEventData(); + + if (event.getEventType() == EVENT_TYPE.VOLUME_OPTION_SET) { + Entry<String, String> eventEntry = (Entry<String, String>) event.getEventData(); if (isNewOption(volume, eventEntry.getKey())) { - // option has been set successfully by the user. re-enable the add button and search filter textbox - addButton.setEnabled(true); + // option has been set successfully by the user. re-enable the add button and search filter + // textbox + setAddButtonsEnabled(true); filterText.setEnabled(true); } - - if(tableViewer.getTable().getItemCount() < volume.getOptions().size()) { + + if (defaultVolumeOptions.size() == volume.getOptions().size()) { + setAddButtonsEnabled(false); + } + + if (tableViewer.getTable().getItemCount() < volume.getOptions().size()) { // new volume set from outside this page. refresh the viewer. tableViewer.refresh(); } else { @@ -209,14 +233,14 @@ public class VolumeOptionsPage extends Composite { } private boolean isNewOption(Volume volume, String optionKey) { - if(filterText.getText().length() > 0) { + if (filterText.getText().length() > 0) { // user has been filtering the contents. adding new option is allowed only when contents are NOT // filtered. Thus it's impossible that this is a newly added option return false; } - + // if this is the last option in the volume options, it must be the new option - return optionKey.equals(volume.getOptions().keySet().toArray()[volume.getOptions().size()-1]); + return optionKey.equals(volume.getOptions().keySet().toArray()[volume.getOptions().size() - 1]); } }; GlusterDataModelManager.getInstance().addClusterListener(clusterListener); @@ -240,7 +264,7 @@ public class VolumeOptionsPage extends Composite { setColumnProperties(table, OPTIONS_TABLE_COLUMN_INDICES.OPTION_KEY, SWT.CENTER, 100); setColumnProperties(table, OPTIONS_TABLE_COLUMN_INDICES.OPTION_VALUE, SWT.CENTER, 100); } - + private TableColumnLayout createTableColumnLayout() { TableColumnLayout tableColumnLayout = new TableColumnLayout(); ColumnLayoutData defaultColumnLayoutData = new ColumnWeightData(100); @@ -250,7 +274,7 @@ public class VolumeOptionsPage extends Composite { return tableColumnLayout; } - + private TableColumn createValueColumn() { TableViewerColumn valueColumn = new TableViewerColumn(tableViewer, SWT.NONE); valueColumn.getColumn() @@ -262,10 +286,10 @@ public class VolumeOptionsPage extends Composite { return ((Entry<String, String>) element).getValue(); } }); - + // User can edit value of a volume option valueColumn.setEditingSupport(new OptionValueEditingSupport(valueColumn.getViewer(), volume)); - + return valueColumn.getColumn(); } @@ -278,26 +302,26 @@ public class VolumeOptionsPage extends Composite { public String getText(Object element) { return ((Entry<String, String>) element).getKey(); } - + @SuppressWarnings("unchecked") @Override public String getToolTipText(Object element) { String key = ((Entry<String, String>) element).getKey(); - if(key.isEmpty()) { + if (key.isEmpty()) { return "Click to select a volume option key"; } - + VolumeOptionInfo optionInfo = GlusterDataModelManager.getInstance().getVolumeOptionInfo(key); - // Wrap the description before adding to tooltip so that long descriptions are displayed properly + // Wrap the description before adding to tooltip so that long descriptions are displayed properly return WordUtils.wrap(optionInfo.getDescription(), 60) + CoreConstants.NEWLINE + "Default value: " + optionInfo.getDefaultValue(); } }); - + // Editing support required when adding new key keyEditingSupport = new OptionKeyEditingSupport(keyColumn.getViewer(), volume); keyColumn.setEditingSupport(keyEditingSupport); - + return keyColumn.getColumn(); } diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/ServersPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/ServersPage.java index 6be3e78c..20c3cbd4 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/ServersPage.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/ServersPage.java @@ -1,4 +1,4 @@ -/******************************************************************************* + /******************************************************************************* * Copyright (c) 2011 Gluster, Inc. <http://www.gluster.com> * This file is part of Gluster Management Console. * @@ -22,7 +22,6 @@ import org.eclipse.jface.layout.TableColumnLayout; import org.eclipse.jface.viewers.CheckboxTableViewer; import org.eclipse.jface.viewers.ColumnWeightData; import org.eclipse.jface.viewers.IDoubleClickListener; -import org.eclipse.jface.viewers.TableViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; @@ -39,6 +38,9 @@ import org.eclipse.swt.widgets.Text; import org.eclipse.ui.IWorkbenchSite; import org.eclipse.ui.forms.widgets.FormToolkit; +import com.gluster.storage.management.client.GlusterDataModelManager; +import com.gluster.storage.management.core.model.ClusterListener; +import com.gluster.storage.management.core.model.DefaultClusterListener; import com.gluster.storage.management.core.model.EntityGroup; import com.gluster.storage.management.core.model.Server; import com.gluster.storage.management.gui.EntityGroupContentProvider; @@ -48,7 +50,7 @@ import com.gluster.storage.management.gui.utils.GUIHelper; public class ServersPage extends Composite { private final FormToolkit toolkit = new FormToolkit(Display.getCurrent()); - private TableViewer tableViewer; + private CheckboxTableViewer tableViewer; private GUIHelper guiHelper = GUIHelper.getInstance(); public enum SERVER_TABLE_COLUMN_INDICES { @@ -81,6 +83,10 @@ public class ServersPage extends Composite { setupPage(site, servers); parent.layout(); // Important - this actually paints the table + createListeners(parent); + } + + private void createListeners(final Composite parent) { /** * Ideally not required. However the table viewer is not getting laid out properly on performing * "maximize + restore" So this is a hack to make sure that the table is laid out again on re-size of the window @@ -92,6 +98,33 @@ public class ServersPage extends Composite { parent.layout(); } }); + + final ClusterListener clusterListener = new DefaultClusterListener() { + @Override + public void discoveredServerRemoved(Server server) { + refreshViewer(); + } + + @Override + public void discoveredServerAdded(Server server) { + refreshViewer(); + } + + private void refreshViewer() { + tableViewer.refresh(); + parent.update(); + } + }; + + final GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance(); + modelManager.addClusterListener(clusterListener); + addDisposeListener(new DisposeListener() { + @Override + public void widgetDisposed(DisposeEvent e) { + toolkit.dispose(); + modelManager.removeClusterListener(clusterListener); + } + }); } public void setInput(EntityGroup<Server> servers) { @@ -128,14 +161,17 @@ public class ServersPage extends Composite { // setColumnProperties(table, SERVER_DISK_TABLE_COLUMN_INDICES.DISK_SPACE_IN_USE, SWT.CENTER, 90); } - private TableViewer createServerTableViewer(Composite parent) { - TableViewer tableViewer = CheckboxTableViewer.newCheckList(parent, SWT.FLAT | SWT.FULL_SELECTION | SWT.MULTI); + private CheckboxTableViewer createServerTableViewer(Composite parent) { + final CheckboxTableViewer tableViewer = CheckboxTableViewer.newCheckList(parent, SWT.FLAT | SWT.FULL_SELECTION | SWT.MULTI); // TableViewer tableViewer = new TableViewer(parent, SWT.FLAT | SWT.FULL_SELECTION | SWT.MULTI); tableViewer.setLabelProvider(new ServerTableLabelProvider()); tableViewer.setContentProvider(new EntityGroupContentProvider<Server>()); setupServerTable(parent, tableViewer.getTable()); + // make sure that table selection is driven by checkbox selection + guiHelper.configureCheckboxTableViewer(tableViewer); + return tableViewer; } |
