/******************************************************************************* * Copyright (c) 2006-2011 Gluster, Inc. * This file is part of Gluster Management Console. * * Gluster Management Console is free software; you can redistribute * it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * Gluster Management Console is distributed in the hope that it * will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * . *******************************************************************************/ package org.gluster.storage.management.console.actions; import java.util.ArrayList; import java.util.List; import java.util.Set; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.action.IAction; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.viewers.ISelection; import org.gluster.storage.management.client.VolumesClient; import org.gluster.storage.management.console.GlusterDataModelManager; import org.gluster.storage.management.console.IImageKeys; import org.gluster.storage.management.console.utils.GUIHelper; import org.gluster.storage.management.core.constants.CoreConstants; import org.gluster.storage.management.core.model.Volume; import org.gluster.storage.management.core.model.Volume.VOLUME_STATUS; public class DeleteVolumeAction extends AbstractMonitoredActionDelegate { private GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance(); private List selectedVolumes = new ArrayList(); private List selectedVolumeNames = new ArrayList(); private List onlineVolumeNames = new ArrayList(); private List deletedVolumeNames = new ArrayList(); private List failedVolumes = new ArrayList(); @Override protected void performAction(final IAction action, IProgressMonitor monitor) { final String actionDesc = action.getDescription(); collectVolumeNames(); String warningMessage; List cifsVolumes = GlusterDataModelManager.getInstance().getCifsEnabledVolumeNames(selectedVolumes); List offlineServers = GlusterDataModelManager.getInstance().getOfflineServers(); // One or more servers are offline, Show warning if cifs is enabled if (cifsVolumes != null && cifsVolumes.size() > 0 && offlineServers != null && offlineServers.size() > 0) { Integer userAction = new MessageDialog(getShell(), "CIFS configuration", GUIHelper.getInstance().getImage( IImageKeys.VOLUME_16x16), "Performing CIFS updates when one or more servers are offline can trigger " + "inconsistent behavior for CIFS accesses in the cluster." + CoreConstants.NEWLINE + "Are you sure you want to continue?", MessageDialog.QUESTION, new String[] { "No", "Yes" }, -1).open(); if (userAction != 1) { return; // Do not delete volume services } } if (onlineVolumeNames.size() > 0) { // Getting confirmation for stop and delete warningMessage = "Following volume(s) " + onlineVolumeNames + " are online, " + CoreConstants.NEWLINE + "Are you sure to continue?" + CoreConstants.NEWLINE + selectedVolumeNames; } else { warningMessage = "Are you sure to delete the volumes " + selectedVolumeNames + " ?"; } final Integer deleteOption = new MessageDialog(getShell(), "Delete Volume", GUIHelper.getInstance() .getImage(IImageKeys.VOLUME_16x16), 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; } String errorMessage = deleteVolumes(selectedVolumes, deleteOption, monitor); // Display the success or failure info if (deletedVolumeNames.size() == 0) { // No volume(s) deleted successfully showErrorDialog(actionDesc, "Volume(s) could not be deleted! " + CoreConstants.NEWLINE + errorMessage); } else { String info = "Volume(s) " + deletedVolumeNames + " deleted successfully!"; if (!failedVolumes.isEmpty()) { info += CoreConstants.NEWLINE + CoreConstants.NEWLINE + "Volumes " + failedVolumes + " could not be deleted!" + CoreConstants.NEWLINE + errorMessage; } if (selectedVolumes.size() == deletedVolumeNames.size()) { showInfoDialog(actionDesc, info); } else { showWarningDialog(actionDesc, info); } } } private String deleteVolumes(List volumes, final Integer deleteOption, IProgressMonitor monitor) { deletedVolumeNames.clear(); failedVolumes.clear(); VolumesClient vc = new VolumesClient(); boolean confirmDeleteDir = (deleteOption == 1) ? true : false; String errorMessage = ""; // To calculate the total work we need to sum volumes size + online volumes (because we treat stop and delete as // separate steps) List onlineVolumes = getOnlineVolumes(volumes); monitor.beginTask("Deleting Selected Volumes...", volumes.size() + onlineVolumes.size()); // Deletion of a volume results in changes to the model, and ultimately updates the "selectedVolumes" list, // over which we are iterating, thus resulting in ConcurrentModificationException. To avoid this, we iterate // over an array obtained from the list. for (Volume volume : volumes.toArray(new Volume[0])) { if (volume.getStatus() == VOLUME_STATUS.ONLINE) { // stop if online volume monitor.setTaskName("Stopping volume [" + volume.getName() + "]"); try { vc.stopVolume(volume.getName(), false); } catch (Exception e1) { // try again with force = true try { vc.stopVolume(volume.getName(), true); } catch(Exception e2) { // force stop also failed. // Mark as deletion failed, append error message. errorMessage += CoreConstants.NEWLINE + "Stop [" + volume.getName() + "] : [" + e2.getMessage() + "]"; failedVolumes.add(volume); // since we are not going to perform delete on this volume, // mark the deletion task as worked monitor.worked(1); // continue to next volume without trying to delete this one continue; } } finally { // worked for "stop" operation monitor.worked(1); } } monitor.setTaskName("Deleting volume [" + volume.getName() + "]"); try { vc.deleteVolume(volume.getName(), confirmDeleteDir); modelManager.deleteVolume(volume); deletedVolumeNames.add(volume.getName()); } catch (Exception e) { // Volume delete succeeded and post delete operation (directory cleanup, CIFS etc) may fail if (vc.volumeExists(volume.getName())) { errorMessage += CoreConstants.NEWLINE + "Delete [" + volume.getName() + "] : [" + e.getMessage() + "]"; failedVolumes.add(volume); } else { errorMessage += CoreConstants.NEWLINE + "Volume [" + volume.getName() + "] deleted, but following error occured: [" + e.getMessage() + "]"; modelManager.deleteVolume(volume); deletedVolumeNames.add(volume.getName()); } } finally { monitor.worked(1); } } monitor.done(); return errorMessage; } private List getOnlineVolumes(List volumes) { List onlineVolumes = new ArrayList(); for (Volume volume : volumes) { if (volume.getStatus() == VOLUME_STATUS.ONLINE) { onlineVolumes.add(volume); } } return onlineVolumes; } private void collectVolumeNames() { selectedVolumeNames.clear(); onlineVolumeNames.clear(); for (Volume volume : selectedVolumes) { selectedVolumeNames.add(volume.getName()); if (volume.getStatus() == VOLUME_STATUS.ONLINE) { onlineVolumeNames.add(volume.getName()); } } } @Override public void dispose() { System.out.println("Disposing [" + this.getClass().getSimpleName() + "]"); } @Override public void selectionChanged(IAction action, ISelection selection) { Set selectedVolumeSet = GUIHelper.getInstance().getSelectedEntities(getWindow(), Volume.class); selectedVolumes.clear(); if (selectedVolumeSet == null || selectedVolumeSet.isEmpty()) { super.selectionChanged(action, selection); if (selectedEntity instanceof Volume) { selectedVolumes.add((Volume) selectedEntity); } } else { selectedVolumes.addAll(selectedVolumeSet); //TODO reverse the collection to maintain the selected order } action.setEnabled( (selectedVolumes.size() > 0) ); } }