From 3cc0768e0baf35ea140262e4f646cbdb9a3b8b84 Mon Sep 17 00:00:00 2001 From: Selvam Date: Wed, 20 Apr 2011 10:55:26 +0530 Subject: Story #18 Add disk, UI, REST client and REST Resource --- .../management/client/DiscoveredServersClient.java | 1 + .../storage/management/client/VolumesClient.java | 27 +- .../management/core/constants/RESTConstants.java | 2 + .../storage/management/core/model/Volume.java | 8 +- .../management/core/utils/GlusterCoreUtil.java | 38 +++ .../storage/management/core/utils/StringUtil.java | 21 +- src/com.gluster.storage.management.gui/plugin.xml | 32 +- .../management/gui/actions/AddDiskAction.java | 83 ++++++ .../management/gui/dialogs/AddDiskPage.java | 160 ++++++++++ .../management/gui/dialogs/AddDiskWizard.java | 88 ++++++ .../gui/dialogs/CreateVolumeDisksPage.java | 319 -------------------- .../management/gui/dialogs/DisksSelectionPage.java | 322 +++++++++++++++++++++ .../management/gui/dialogs/SelectDisksDialog.java | 24 +- .../server/resources/VolumesResource.java | 41 ++- .../management/server/utils/GlusterUtil.java | 89 ++++-- 15 files changed, 872 insertions(+), 383 deletions(-) create mode 100644 src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/GlusterCoreUtil.java create mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/AddDiskAction.java create mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/AddDiskPage.java create mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/AddDiskWizard.java delete mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/CreateVolumeDisksPage.java create mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/DisksSelectionPage.java (limited to 'src') diff --git a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/DiscoveredServersClient.java b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/DiscoveredServersClient.java index eb6ef3a0..c7ea7507 100644 --- a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/DiscoveredServersClient.java +++ b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/DiscoveredServersClient.java @@ -46,6 +46,7 @@ public class DiscoveredServersClient extends AbstractClient { MultivaluedMap queryParams = new MultivaluedMapImpl(); queryParams.putSingle("details", getDetails.toString()); + //System.out.println((String) fetchResource(queryParams, String.class)); return ((Response) fetchResource(queryParams, responseClass)).getData(); } diff --git a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/VolumesClient.java b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/VolumesClient.java index 05b89306..aaba73a8 100644 --- a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/VolumesClient.java +++ b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/VolumesClient.java @@ -20,11 +20,18 @@ */ package com.gluster.storage.management.client; +import java.util.ArrayList; +import java.util.List; + import com.gluster.storage.management.core.constants.RESTConstants; +import com.gluster.storage.management.core.model.Disk; import com.gluster.storage.management.core.model.Status; import com.gluster.storage.management.core.model.Volume; +import com.gluster.storage.management.core.model.Disk.DISK_STATUS; import com.gluster.storage.management.core.response.VolumeListResponse; import com.gluster.storage.management.core.response.VolumeOptionInfoListResponse; +import com.gluster.storage.management.core.utils.GlusterCoreUtil; +import com.gluster.storage.management.core.utils.StringUtil; import com.sun.jersey.api.representation.Form; public class VolumesClient extends AbstractClient { @@ -84,6 +91,13 @@ public class VolumesClient extends AbstractClient { return ((VolumeOptionInfoListResponse) fetchSubResource(RESTConstants.SUBRESOURCE_DEFAULT_OPTIONS, VolumeOptionInfoListResponse.class)); } + + public Status addDisks(String volumeName, List diskList) { + String disks = StringUtil.ListToString( GlusterCoreUtil.getQualifiedDiskNames(diskList), ","); + Form form = new Form(); + form.add(RESTConstants.QUERY_PARAM_DISKS, disks); + return (Status) postRequest(volumeName + "/" + RESTConstants.SUBRESOURCE_DISKS, Status.class, form); + } public static void main(String[] args) { UsersClient usersClient = new UsersClient(); @@ -105,8 +119,17 @@ public class VolumesClient extends AbstractClient { // for (VolumeOptionInfo option : client.getVolumeOptionsDefaults()) { // System.out.println(option.getName() + "-" + option.getDescription() + "-" + option.getDefaultValue()); // } - System.out.println(client.getVolume("Volume3").getOptions()); - System.out.println(client.setVolumeOption("Volume3", "network.frame-timeout", "600").getMessage()); +// System.out.println(client.getVolume("Volume3").getOptions()); +// System.out.println(client.setVolumeOption("Volume3", "network.frame-timeout", "600").getMessage()); + List disks = new ArrayList(); + Disk disk = new Disk(); + disk.setServerName("server1"); + disk.setName("sda"); + disk.setStatus(DISK_STATUS.READY); + disks.add(disk); + + Status status = client.addDisks("Volume3", disks); + System.out.println(status.getMessage()); } } } diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/constants/RESTConstants.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/constants/RESTConstants.java index 0aa286a3..4bd0d292 100644 --- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/constants/RESTConstants.java +++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/constants/RESTConstants.java @@ -29,6 +29,7 @@ public class RESTConstants { public static final String SUBRESOURCE_DEFAULT_OPTIONS = "defaultoptions"; public static final String SUBRESOURCE_OPTIONS = "options"; public static final String SUBRESOURCE_LOGS = "logs"; + public static final String SUBRESOURCE_DISKS = "disks"; public static final String FORM_PARAM_OPERATION = "operation"; @@ -41,6 +42,7 @@ public class RESTConstants { public static final String FORM_PARAM_DELETE_OPTION = "value"; public static final String QUERY_PARAM_DISK_NAME = "diskName"; + public static final String QUERY_PARAM_DISKS = "disks"; public static final String QUERY_PARAM_LINE_COUNT = "lineCount"; public static final String QUERY_PARAM_VOLUME_NAME = "volumeName"; public static final String QUERY_PARAM_DELETE_OPTION = "deleteOption"; diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/Volume.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/Volume.java index 94b23179..b43381e5 100644 --- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/Volume.java +++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/Volume.java @@ -49,6 +49,10 @@ public class Volume extends Entity { GLUSTERFS, NFS }; + + public static final int DEFAULT_REPLICA_COUNT = 2; + public static final int DEFAULT_STRIPE_COUNT = 4; + public static final String OPTION_AUTH_ALLOW = "auth.allow"; private static final String[] VOLUME_TYPE_STR = new String[] { "Plain Distribute", "Distributed Mirror", @@ -104,9 +108,9 @@ public class Volume extends Entity { // TODO find a way to get the replica / strip count if (volumeType == VOLUME_TYPE.DISTRIBUTED_STRIPE) { setReplicaCount(0); - setStripeCount(3); + setStripeCount(DEFAULT_STRIPE_COUNT); } else if (volumeType == VOLUME_TYPE.DISTRIBUTED_MIRROR) { - setReplicaCount(2); + setReplicaCount(DEFAULT_REPLICA_COUNT); setStripeCount(0); } else { setReplicaCount(0); diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/GlusterCoreUtil.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/GlusterCoreUtil.java new file mode 100644 index 00000000..9e3084fb --- /dev/null +++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/GlusterCoreUtil.java @@ -0,0 +1,38 @@ +/** + * GlusterCoreUtil.java + * + * Copyright (c) 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 Affero 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 Affero General Public License + * for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see + * . + */ +package com.gluster.storage.management.core.utils; + +import java.util.ArrayList; +import java.util.List; + +import com.gluster.storage.management.core.model.Disk; + + +public class GlusterCoreUtil { + // Convert from Disk list to Qualified disk name list + public static final List getQualifiedDiskNames(List diskList) { + List qualifiedDiskNames = new ArrayList(); + for (Disk disk : diskList) { + qualifiedDiskNames.add(disk.getQualifiedName()); + } + return qualifiedDiskNames; + } +} diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/StringUtil.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/StringUtil.java index 45f4c436..8dc5837d 100644 --- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/StringUtil.java +++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/StringUtil.java @@ -18,15 +18,24 @@ *******************************************************************************/ package com.gluster.storage.management.core.utils; +import java.util.List; + public class StringUtil { - public static boolean filterString(String sourceString, - String filterString, boolean caseSensitive) { - return caseSensitive ? sourceString.contains(filterString) - : sourceString.toLowerCase().contains( - filterString.toLowerCase()); + public static boolean filterString(String sourceString, String filterString, boolean caseSensitive) { + return caseSensitive ? sourceString.contains(filterString) : sourceString.toLowerCase().contains( + filterString.toLowerCase()); } - + public static String removeSpaces(String str) { return str.replaceAll("\\s+", ""); } + + public static String ListToString(List list, String delimiter) { + StringBuilder output = new StringBuilder(); + for(String element : list) { + output.append(element).append(delimiter); + } + String outputStr = output.toString(); + return outputStr.substring(0, outputStr.length() - (delimiter.length()+1)); + } } diff --git a/src/com.gluster.storage.management.gui/plugin.xml b/src/com.gluster.storage.management.gui/plugin.xml index 97a60ad1..21dbbf50 100644 --- a/src/com.gluster.storage.management.gui/plugin.xml +++ b/src/com.gluster.storage.management.gui/plugin.xml @@ -251,6 +251,12 @@ id="com.gluster.storage.management.gui.commands.MigrateDisk" name="Migrate Disk"> + + @@ -491,11 +497,11 @@ style="push" toolbarPath="Normal" tooltip="Migrate Disk"> - - - - + + + + + + + * 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 Affero 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 Affero General Public License + * for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see + * . + */ + +package com.gluster.storage.management.gui.actions; + +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.wizard.WizardDialog; +import org.eclipse.swt.widgets.Display; + +import com.gluster.storage.management.core.model.Volume; +import com.gluster.storage.management.gui.dialogs.AddDiskWizard; + +public class AddDiskAction extends AbstractActionDelegate { + private Volume volume; + + /* (non-Javadoc) + * @see org.eclipse.ui.IWorkbenchWindowActionDelegate#dispose() + */ + @Override + public void dispose() { + window = null; + } + + /* (non-Javadoc) + * @see com.gluster.storage.management.gui.actions.AbstractActionDelegate#performAction(org.eclipse.jface.action.IAction) + */ + @Override + protected void performAction(IAction action) { + //TODO: open a dialog box + // MessageDialog.openInformation(getShell(), "Action captured", action.getDescription() + "\n" + volume.getName()); + Display.getDefault().asyncExec(new Runnable() { + + @Override + public void run() { + AddDiskWizard wizard = new AddDiskWizard(volume); // Also add single page + + WizardDialog dialog = new WizardDialog(getShell(), wizard); + dialog.create(); + dialog.getShell().setSize(1024, 600); + dialog.open(); + } + }); + + } + + + /* + * (non-Javadoc) + * + * @see + * com.gluster.storage.management.gui.actions.AbstractActionDelegate#selectionChanged(org.eclipse.jface.action.IAction + * , org.eclipse.jface.viewers.ISelection) + */ + @Override + public void selectionChanged(IAction action, ISelection selection) { + super.selectionChanged(action, selection); + + if (selectedEntity instanceof Volume) { + this.volume = (Volume) selectedEntity; + // action.setEnabled(volume.getStatus() == VOLUME_STATUS.ONLINE); + } + } + +} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/AddDiskPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/AddDiskPage.java new file mode 100644 index 00000000..ea86774f --- /dev/null +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/AddDiskPage.java @@ -0,0 +1,160 @@ +/** + * AddDiskPage.java + * + * Copyright (c) 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 Affero 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 Affero General Public License + * for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see + * . + */ +package com.gluster.storage.management.gui.dialogs; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; + +import com.gluster.storage.management.client.GlusterDataModelManager; +import com.gluster.storage.management.core.model.Disk; +import com.gluster.storage.management.core.model.Volume; +import com.gluster.storage.management.core.model.Volume.VOLUME_TYPE; +import com.richclientgui.toolbox.duallists.DualListComposite.ListContentChangedListener; +import com.richclientgui.toolbox.duallists.IRemovableContentProvider; + +/** + * @author root + * + */ +public class AddDiskPage extends WizardPage { + private List availableDisks = new ArrayList(); + private List selectedDisks = new ArrayList(); + private Volume volume = null; + private DisksSelectionPage page = null; + + public static final String PAGE_NAME = "add.disk.volume.page"; + + /** + * @param pageName + */ + protected AddDiskPage(Volume volume) { + super(PAGE_NAME); + this.volume = volume; + setTitle("Add Disk"); + + String description = "Add disks to the Volume by choosing disks from the cluster servers.\n"; + if ( volume.getVolumeType() == VOLUME_TYPE.DISTRIBUTED_MIRROR) { + description += "(Disk selection should be multiples of " + volume.getReplicaCount() + ")"; + } else if (volume.getVolumeType() == VOLUME_TYPE.DISTRIBUTED_STRIPE) { + description += "(Disk selection should be multiples of " + volume.getStripeCount() + ")"; + } + setDescription(description); + availableDisks = getAvailableDisks(volume); + + setPageComplete(false); + setErrorMessage("Please select disks to be added to the volume."); + } + + + private boolean isDiskUsed(Volume volume, Disk disk){ + for (String volumeDisk : volume.getDisks()) { // expected form of volumeDisk is "server:diskName" + if ( disk.getQualifiedName().equals(volumeDisk)) { + return true; + } + } + return false; + } + + protected List getAvailableDisks(Volume volume) { + List availableDisks = new ArrayList(); + for (Disk disk : GlusterDataModelManager.getInstance().getReadyDisksOfAllServers()) { + if ( ! isDiskUsed(volume, disk) ) { + availableDisks.add(disk); + } + } + return availableDisks; + } + + public List getChosenDisks( ) { + return page.getChosenDisks(); + } + + private boolean isValidDiskSelection(int diskCount) { + if ( diskCount == 0) { + return false; + } + switch (volume.getVolumeType()) { + case DISTRIBUTED_MIRROR: + return (diskCount % volume.getReplicaCount() == 0); + case DISTRIBUTED_STRIPE: + return (diskCount % volume.getStripeCount() == 0); + } + return true; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite) + */ + @Override + public void createControl(Composite parent) { + getShell().setText("Add Disk"); + List chosenDisks = new ArrayList(); // or volume.getDisks(); + + page = new DisksSelectionPage(parent, SWT.NONE, availableDisks, chosenDisks); + page.addDiskSelectionListener(new ListContentChangedListener() { + @Override + public void listContentChanged(IRemovableContentProvider contentProvider) { + List newChosenDisks = page.getChosenDisks(); + + // validate chosen disks + if(isValidDiskSelection(newChosenDisks.size())) { + clearError(); + } else { + setError(); + } + } + }); + setControl(page); + } + + private void setError() { + String errorMessage = null; + if ( volume.getVolumeType() == VOLUME_TYPE.PLAIN_DISTRIBUTE) { + errorMessage = "Please select at least one disk!"; + } else if( volume.getVolumeType() == VOLUME_TYPE.DISTRIBUTED_MIRROR) { + errorMessage = "Please select disks in multiples of " + volume.getReplicaCount(); + } else { + errorMessage = "Please select disks in multiples of " + volume.getStripeCount(); + } + + setPageComplete(false); + setErrorMessage(errorMessage); + } + + private void clearError() { + setErrorMessage(null); + setPageComplete(true); + } + + public DisksSelectionPage getDialogPage() { + return this.page; + } + + public void setPageComplete() { + + } +} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/AddDiskWizard.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/AddDiskWizard.java new file mode 100644 index 00000000..e12f6a57 --- /dev/null +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/AddDiskWizard.java @@ -0,0 +1,88 @@ +/** + * AddDiskWizard.java + * + * Copyright (c) 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 Affero 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 Affero General Public License + * for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see + * . + */ +package com.gluster.storage.management.gui.dialogs; + +import java.util.List; + +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.wizard.Wizard; + +import com.gluster.storage.management.client.GlusterDataModelManager; +import com.gluster.storage.management.client.VolumesClient; +import com.gluster.storage.management.core.model.Disk; +import com.gluster.storage.management.core.model.Status; +import com.gluster.storage.management.core.model.Volume; +import com.gluster.storage.management.core.utils.GlusterCoreUtil; + +/** + * + */ +public class AddDiskWizard extends Wizard { + private AddDiskPage page; + private Volume volume; + + public AddDiskWizard(Volume volume) { + setWindowTitle("Gluster Management Console - Add disk"); + setHelpAvailable(false); // TODO: Introduce wizard help + this.volume = volume; + } + + public void addPages() { + page = new AddDiskPage(volume); + addPage(page); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.wizard.Wizard#performFinish() + */ + @Override + public boolean performFinish() { + List disks = page.getChosenDisks(); + VolumesClient volumeClient = new VolumesClient(GlusterDataModelManager.getInstance().getSecurityToken()); + try { + Status status = volumeClient.addDisks(volume.getName(), disks); + if (!status.isSuccess()) { + MessageDialog.openError(getShell(), "Add disk(s) to Volume", status.getMessage()); + return status.isSuccess(); + } else { + volume.addDisks(GlusterCoreUtil.getQualifiedDiskNames(disks)); + MessageDialog.openInformation(getShell(), "Add disk(s) to Volume", "Disk(s) are successfully added to " + + volume.getName()); + return status.isSuccess(); + } + } catch (Exception e) { + MessageDialog.openError(getShell(), "Add disk(s) to Volume", e.getMessage()); + return false; + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.wizard.Wizard#canFinish() + */ + @Override + public boolean canFinish() { + return super.canFinish() && page.isPageComplete(); + } +} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/CreateVolumeDisksPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/CreateVolumeDisksPage.java deleted file mode 100644 index c78601d9..00000000 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/CreateVolumeDisksPage.java +++ /dev/null @@ -1,319 +0,0 @@ -/******************************************************************************* - * Copyright (c) 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 Affero 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 Affero General Public License - * for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see - * . - *******************************************************************************/ -package com.gluster.storage.management.gui.dialogs; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.eclipse.jface.viewers.ITableLabelProvider; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.KeyAdapter; -import org.eclipse.swt.events.KeyEvent; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.TableItem; -import org.eclipse.swt.widgets.Text; - -import com.gluster.storage.management.core.model.Disk; -import com.gluster.storage.management.core.utils.NumberUtil; -import com.gluster.storage.management.gui.IImageKeys; -import com.gluster.storage.management.gui.TableLabelProviderAdapter; -import com.gluster.storage.management.gui.utils.EntityViewerFilter; -import com.gluster.storage.management.gui.utils.GUIHelper; -import com.richclientgui.toolbox.duallists.CustomTableDualListComposite; -import com.richclientgui.toolbox.duallists.DualListComposite.ListContentChangedListener; -import com.richclientgui.toolbox.duallists.IRemovableContentProvider; -import com.richclientgui.toolbox.duallists.RemovableContentProvider; -import com.richclientgui.toolbox.duallists.TableColumnData; - -public class CreateVolumeDisksPage extends Composite { - private enum DISK_TABLE_COLUMN_INDICES { - SERVER, DISK, SPACE, SPACE_USED - } - - private static final String[] DISK_TABLE_COLUMNS_NAMES = { "Server", "Disk", "Space (GB)", "Used Space (GB)" }; - - private GUIHelper guiHelper = GUIHelper.getInstance(); - private CustomTableDualListComposite dualTableViewer; - private Text filterText; - // This list keeps track of the order of the disks as user changes the same by clicking on up/down arrow buttons - private List chosenDisks = new ArrayList(); - - private IRemovableContentProvider chosenDisksContentProvider; - - private Button btnUp; - - private Button btnDown; - - public CreateVolumeDisksPage(final Composite parent, int style, List allDisks, List selectedDisks) { - super(parent, style); - - createPage(allDisks, selectedDisks); - - parent.layout(); - } - - private TableLabelProviderAdapter getDiskLabelProvider() { - return new TableLabelProviderAdapter() { - - @Override - public String getColumnText(Object element, int columnIndex) { - if (!(element instanceof Disk)) { - return null; - } - - Disk disk = (Disk) element; - return (columnIndex == DISK_TABLE_COLUMN_INDICES.SERVER.ordinal() ? disk.getServerName() - : columnIndex == DISK_TABLE_COLUMN_INDICES.DISK.ordinal() ? disk.getName() - : columnIndex == DISK_TABLE_COLUMN_INDICES.SPACE.ordinal() ? NumberUtil - .formatNumber(disk.getSpace()) - : columnIndex == DISK_TABLE_COLUMN_INDICES.SPACE_USED.ordinal() ? NumberUtil - .formatNumber(disk.getSpaceInUse()) : "Invalid"); - } - }; - } - - private int indexOf(List disks, Disk searchDisk) { - for(Disk disk : disks) { - if(disk.getQualifiedName().equals(searchDisk.getQualifiedName())) { - return disks.indexOf(disk); - } - } - return -1; - } - - private void createPage(List allDisks, List selectedDisks) { - setupPageLayout(); - - filterText = guiHelper.createFilterText(this); - new Label(this, SWT.NONE); - - createDualTableViewer(allDisks, selectedDisks); - createFilter(filterText, false); // attach filter text to the dual table viewer for auto-filtering - - Composite buttonContainer = new Composite(this, SWT.NONE); - buttonContainer.setLayout(new GridLayout(1, false)); - GridData buttonContainerData = new GridData(SWT.FILL, SWT.CENTER, true, true); - buttonContainerData.minimumWidth = 40; - buttonContainer.setLayoutData(buttonContainerData); - - btnUp = new Button(buttonContainer, SWT.TOGGLE); - GridData btnUpData = new GridData(SWT.LEFT, SWT.BOTTOM, true, false); - btnUpData.minimumWidth = 30; - btnUp.setLayoutData(btnUpData); - btnUp.setImage(guiHelper.getImage(IImageKeys.ARROW_UP)); - btnUp.addSelectionListener(new SelectionAdapter() { - - @Override - public void widgetSelected(SelectionEvent e) { - chosenDisks = getChosenDisks(); - List selectedDisks = getSelectedChosenDisks(); - - chosenDisksContentProvider.removeElements(chosenDisks); - for(Disk disk : selectedDisks) { - int index = chosenDisks.indexOf(disk); - Disk diskAbove = chosenDisks.get(index - 1); - chosenDisks.set(index - 1, disk); - chosenDisks.set(index, diskAbove); - } - chosenDisksContentProvider.addElements(chosenDisks); - dualTableViewer.refreshChosenViewer(); - updateButtons(); - } - }); - - btnDown = new Button(buttonContainer, SWT.TOGGLE); - btnDown.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, false)); - btnDown.setImage(guiHelper.getImage(IImageKeys.ARROW_DOWN)); - btnDown.addSelectionListener(new SelectionAdapter() { - - @Override - public void widgetSelected(SelectionEvent e) { - - chosenDisks = getChosenDisks(); - List selectedDisks = getSelectedChosenDisks(); - - chosenDisksContentProvider.removeElements(chosenDisks); - for(Disk disk : selectedDisks) { - int index = chosenDisks.indexOf(disk); - Disk diskBelow = chosenDisks.get(index + 1); - chosenDisks.set(index + 1, disk); - chosenDisks.set(index, diskBelow); - } - chosenDisksContentProvider.addElements(chosenDisks); - dualTableViewer.refreshChosenViewer(); - updateButtons(); - - } - }); - } - - private List getSelectedChosenDisks() { - TableItem[] selectedItems = dualTableViewer.getChosenTable().getSelection(); - List selectedDisks = new ArrayList(); - for (TableItem item : selectedItems) { - selectedDisks.add((Disk)item.getData()); - } - return selectedDisks; - } - - private void createFilter(final Text filterText, boolean caseSensitive) { - final String initialFilterString = filterText.getText(); - - final EntityViewerFilter filter = new EntityViewerFilter(initialFilterString, caseSensitive); - // On every keystroke inside the text field, update the filter string - filterText.addKeyListener(new KeyAdapter() { - private String filterString = initialFilterString; - - @Override - public void keyReleased(KeyEvent e) { - String enteredString = filterText.getText(); - if (enteredString.equals(filterString)) { - // Filter string has not changed. don't do anything - return; - } - - // Update filter string - filterString = enteredString; - filter.setFilterString(filterString); - - // Refresh viewer with newly filtered content - dualTableViewer.refreshAvailableViewer(); - dualTableViewer.refreshChosenViewer(); - } - }); - - dualTableViewer.setAvailableViewerFilter(filter); - dualTableViewer.setChosenViewerFilter(filter); - } - - private void createDualTableViewer(List allDisks, List selectedDisks) { - TableColumnData[] columnData = createColumnData(); - ITableLabelProvider diskLabelProvider = getDiskLabelProvider(); - - dualTableViewer = new CustomTableDualListComposite(this, SWT.NONE, columnData, columnData); - - dualTableViewer.setViewerLabels("Available:", "Chosen:"); - - dualTableViewer.setAvailableTableLinesVisible(false); - dualTableViewer.setAvailableTableHeaderVisible(true); - dualTableViewer.setAvailableContentProvider(new RemovableContentProvider(getAvailableDisks(allDisks, - selectedDisks))); - dualTableViewer.setAvailableLabelProvider(diskLabelProvider); - - dualTableViewer.setChosenTableLinesVisible(true); - dualTableViewer.setChosenTableHeaderVisible(true); - - chosenDisksContentProvider = new RemovableContentProvider(selectedDisks); - dualTableViewer.setChosenContentProvider(chosenDisksContentProvider); - dualTableViewer.setChosenLabelProvider(diskLabelProvider); - - dualTableViewer.getChosenTable().addSelectionListener(new SelectionAdapter() { - /* (non-Javadoc) - * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) - */ - @Override - public void widgetSelected(SelectionEvent e) { - updateButtons(); - } - }); - } - - private void updateButtons() { - btnUp.setEnabled(true); - btnDown.setEnabled(true); - List selectedChosenDisks = getSelectedChosenDisks(); - List chosenDisks = getChosenDisks(); - for(Disk disk : selectedChosenDisks) { - int index = chosenDisks.indexOf(disk); - if(index == 0) { - btnUp.setEnabled(false); - } - if(index == chosenDisks.size() - 1) { - btnDown.setEnabled(false); - } - } - } - - /** - * @param allDisks - * @param selectedDisks - * @return - */ - private List getAvailableDisks(List allDisks, List selectedDisks) { - List availableDisks = new ArrayList(); - for (Disk disk : allDisks) { - if (!selectedDisks.contains(disk)) { - availableDisks.add(disk); - } - } - return availableDisks; - } - - private TableColumnData[] createColumnData() { - DISK_TABLE_COLUMN_INDICES[] columns = DISK_TABLE_COLUMN_INDICES.values(); - TableColumnData[] columnData = new TableColumnData[columns.length]; - - for (DISK_TABLE_COLUMN_INDICES column : columns) { - int columnNum = column.ordinal(); - columnData[columnNum] = new TableColumnData(columnNum, DISK_TABLE_COLUMNS_NAMES[columnNum], 100); - } - return columnData; - } - - private void setupPageLayout() { - final GridLayout layout = new GridLayout(2, false); - layout.verticalSpacing = 10; - layout.marginTop = 10; - setLayout(layout); - - setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - } - - - public List getChosenDisks() { - Object[] disksArr = (Object[]) chosenDisksContentProvider.getElements(dualTableViewer); - if (disksArr != null) { - List disks = new ArrayList(); - for (Object disk : disksArr) { - disks.add( (Disk)disk ); - } - return disks; - } - return null; - } - - public List getChosenBricks() { - Object[] disksArr = (Object[]) chosenDisksContentProvider.getElements(dualTableViewer); - if (disksArr != null) { - List disks = new ArrayList(); - for (Object disk : disksArr) { - disks.add( ((Disk)disk).getServerName() + ":" + ((Disk)disk).getName() ); // Format: Server:disk - } - return disks; - } - return null; - } -} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/DisksSelectionPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/DisksSelectionPage.java new file mode 100644 index 00000000..e50e81a7 --- /dev/null +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/DisksSelectionPage.java @@ -0,0 +1,322 @@ +/******************************************************************************* + * Copyright (c) 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 Affero 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 Affero General Public License + * for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see + * . + *******************************************************************************/ +package com.gluster.storage.management.gui.dialogs; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.KeyAdapter; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.TableItem; +import org.eclipse.swt.widgets.Text; + +import com.gluster.storage.management.core.model.Disk; +import com.gluster.storage.management.core.utils.NumberUtil; +import com.gluster.storage.management.gui.IImageKeys; +import com.gluster.storage.management.gui.TableLabelProviderAdapter; +import com.gluster.storage.management.gui.utils.EntityViewerFilter; +import com.gluster.storage.management.gui.utils.GUIHelper; +import com.richclientgui.toolbox.duallists.CustomTableDualListComposite; +import com.richclientgui.toolbox.duallists.DualListComposite.ListContentChangedListener; +import com.richclientgui.toolbox.duallists.IRemovableContentProvider; +import com.richclientgui.toolbox.duallists.RemovableContentProvider; +import com.richclientgui.toolbox.duallists.TableColumnData; + +public class DisksSelectionPage extends Composite { + private enum DISK_TABLE_COLUMN_INDICES { + SERVER, DISK, SPACE, SPACE_USED + } + + private static final String[] DISK_TABLE_COLUMNS_NAMES = { "Server", "Disk", "Space (GB)", "Used Space (GB)" }; + + private GUIHelper guiHelper = GUIHelper.getInstance(); + private CustomTableDualListComposite dualTableViewer; + private Text filterText; + // This list keeps track of the order of the disks as user changes the same by clicking on up/down arrow buttons + private List chosenDisks = new ArrayList(); + + private IRemovableContentProvider chosenDisksContentProvider; + + private Button btnUp; + + private Button btnDown; + + public DisksSelectionPage(final Composite parent, int style, List allDisks, List selectedDisks) { + super(parent, style); + + createPage(allDisks, selectedDisks); + + parent.layout(); + } + + public void addDiskSelectionListener(ListContentChangedListener listener) { + dualTableViewer.addChosenListChangedSelectionListener(listener); + } + + private TableLabelProviderAdapter getDiskLabelProvider() { + return new TableLabelProviderAdapter() { + + @Override + public String getColumnText(Object element, int columnIndex) { + if (!(element instanceof Disk)) { + return null; + } + + Disk disk = (Disk) element; + return (columnIndex == DISK_TABLE_COLUMN_INDICES.SERVER.ordinal() ? disk.getServerName() + : columnIndex == DISK_TABLE_COLUMN_INDICES.DISK.ordinal() ? disk.getName() + : columnIndex == DISK_TABLE_COLUMN_INDICES.SPACE.ordinal() ? NumberUtil + .formatNumber(disk.getSpace()) + : columnIndex == DISK_TABLE_COLUMN_INDICES.SPACE_USED.ordinal() ? NumberUtil + .formatNumber(disk.getSpaceInUse()) : "Invalid"); + } + }; + } + + private int indexOf(List disks, Disk searchDisk) { + for(Disk disk : disks) { + if(disk.getQualifiedName().equals(searchDisk.getQualifiedName())) { + return disks.indexOf(disk); + } + } + return -1; + } + + private void createPage(List allDisks, List selectedDisks) { + setupPageLayout(); + + filterText = guiHelper.createFilterText(this); + new Label(this, SWT.NONE); + + createDualTableViewer(allDisks, selectedDisks); + createFilter(filterText, false); // attach filter text to the dual table viewer for auto-filtering + + Composite buttonContainer = new Composite(this, SWT.NONE); + buttonContainer.setLayout(new GridLayout(1, false)); + GridData buttonContainerData = new GridData(SWT.FILL, SWT.CENTER, true, true); + buttonContainerData.minimumWidth = 40; + buttonContainer.setLayoutData(buttonContainerData); + + btnUp = new Button(buttonContainer, SWT.TOGGLE); + GridData btnUpData = new GridData(SWT.LEFT, SWT.BOTTOM, true, false); + btnUpData.minimumWidth = 30; + btnUp.setLayoutData(btnUpData); + btnUp.setImage(guiHelper.getImage(IImageKeys.ARROW_UP)); + btnUp.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + chosenDisks = getChosenDisks(); + List selectedDisks = getSelectedChosenDisks(); + + chosenDisksContentProvider.removeElements(chosenDisks); + for(Disk disk : selectedDisks) { + int index = chosenDisks.indexOf(disk); + Disk diskAbove = chosenDisks.get(index - 1); + chosenDisks.set(index - 1, disk); + chosenDisks.set(index, diskAbove); + } + chosenDisksContentProvider.addElements(chosenDisks); + dualTableViewer.refreshChosenViewer(); + updateButtons(); + } + }); + + btnDown = new Button(buttonContainer, SWT.TOGGLE); + btnDown.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, false)); + btnDown.setImage(guiHelper.getImage(IImageKeys.ARROW_DOWN)); + btnDown.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + + chosenDisks = getChosenDisks(); + List selectedDisks = getSelectedChosenDisks(); + + chosenDisksContentProvider.removeElements(chosenDisks); + for(Disk disk : selectedDisks) { + int index = chosenDisks.indexOf(disk); + Disk diskBelow = chosenDisks.get(index + 1); + chosenDisks.set(index + 1, disk); + chosenDisks.set(index, diskBelow); + } + chosenDisksContentProvider.addElements(chosenDisks); + dualTableViewer.refreshChosenViewer(); + updateButtons(); + + } + }); + } + + private List getSelectedChosenDisks() { + TableItem[] selectedItems = dualTableViewer.getChosenTable().getSelection(); + List selectedDisks = new ArrayList(); + for (TableItem item : selectedItems) { + selectedDisks.add((Disk)item.getData()); + } + return selectedDisks; + } + + private void createFilter(final Text filterText, boolean caseSensitive) { + final String initialFilterString = filterText.getText(); + + final EntityViewerFilter filter = new EntityViewerFilter(initialFilterString, caseSensitive); + // On every keystroke inside the text field, update the filter string + filterText.addKeyListener(new KeyAdapter() { + private String filterString = initialFilterString; + + @Override + public void keyReleased(KeyEvent e) { + String enteredString = filterText.getText(); + if (enteredString.equals(filterString)) { + // Filter string has not changed. don't do anything + return; + } + + // Update filter string + filterString = enteredString; + filter.setFilterString(filterString); + + // Refresh viewer with newly filtered content + dualTableViewer.refreshAvailableViewer(); + dualTableViewer.refreshChosenViewer(); + } + }); + + dualTableViewer.setAvailableViewerFilter(filter); + dualTableViewer.setChosenViewerFilter(filter); + } + + private void createDualTableViewer(List allDisks, List selectedDisks) { + TableColumnData[] columnData = createColumnData(); + ITableLabelProvider diskLabelProvider = getDiskLabelProvider(); + + dualTableViewer = new CustomTableDualListComposite(this, SWT.NONE, columnData, columnData); + + dualTableViewer.setViewerLabels("Available:", "Chosen:"); + + dualTableViewer.setAvailableTableLinesVisible(false); + dualTableViewer.setAvailableTableHeaderVisible(true); + dualTableViewer.setAvailableContentProvider(new RemovableContentProvider(getAvailableDisks(allDisks, + selectedDisks))); + dualTableViewer.setAvailableLabelProvider(diskLabelProvider); + + dualTableViewer.setChosenTableLinesVisible(true); + dualTableViewer.setChosenTableHeaderVisible(true); + + chosenDisksContentProvider = new RemovableContentProvider(selectedDisks); + dualTableViewer.setChosenContentProvider(chosenDisksContentProvider); + dualTableViewer.setChosenLabelProvider(diskLabelProvider); + + dualTableViewer.getChosenTable().addSelectionListener(new SelectionAdapter() { + /* (non-Javadoc) + * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) + */ + @Override + public void widgetSelected(SelectionEvent e) { + updateButtons(); + } + }); + } + + private void updateButtons() { + btnUp.setEnabled(true); + btnDown.setEnabled(true); + List selectedChosenDisks = getSelectedChosenDisks(); + List chosenDisks = getChosenDisks(); + for(Disk disk : selectedChosenDisks) { + int index = chosenDisks.indexOf(disk); + if(index == 0) { + btnUp.setEnabled(false); + } + if(index == chosenDisks.size() - 1) { + btnDown.setEnabled(false); + } + } + } + + /** + * @param allDisks + * @param selectedDisks + * @return + */ + private List getAvailableDisks(List allDisks, List selectedDisks) { + List availableDisks = new ArrayList(); + for (Disk disk : allDisks) { + if (!selectedDisks.contains(disk)) { + availableDisks.add(disk); + } + } + return availableDisks; + } + + private TableColumnData[] createColumnData() { + DISK_TABLE_COLUMN_INDICES[] columns = DISK_TABLE_COLUMN_INDICES.values(); + TableColumnData[] columnData = new TableColumnData[columns.length]; + + for (DISK_TABLE_COLUMN_INDICES column : columns) { + int columnNum = column.ordinal(); + columnData[columnNum] = new TableColumnData(columnNum, DISK_TABLE_COLUMNS_NAMES[columnNum], 100); + } + return columnData; + } + + private void setupPageLayout() { + final GridLayout layout = new GridLayout(2, false); + layout.verticalSpacing = 10; + layout.marginTop = 10; + setLayout(layout); + + setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + } + + + public List getChosenDisks() { + Object[] disksArr = (Object[]) chosenDisksContentProvider.getElements(dualTableViewer); + if (disksArr != null) { + List disks = new ArrayList(); + for (Object disk : disksArr) { + disks.add( (Disk)disk ); + } + return disks; + } + return null; + } + + public List getChosenBricks() { + Object[] disksArr = (Object[]) chosenDisksContentProvider.getElements(dualTableViewer); + if (disksArr != null) { + List disks = new ArrayList(); + for (Object disk : disksArr) { + disks.add( ((Disk)disk).getServerName() + ":" + ((Disk)disk).getName() ); // Format: Server:disk + } + return disks; + } + return null; + } +} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/SelectDisksDialog.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/SelectDisksDialog.java index 0ec19d5b..d88317b1 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/SelectDisksDialog.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/SelectDisksDialog.java @@ -24,7 +24,6 @@ import java.util.List; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.osgi.framework.internal.core.Msg; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridData; @@ -33,13 +32,11 @@ import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Shell; -import com.gluster.storage.management.client.GlusterDataModelManager; import com.gluster.storage.management.core.model.Disk; -import com.gluster.storage.management.core.model.Volume; public class SelectDisksDialog extends Dialog { - private CreateVolumeDisksPage disksPage; + private DisksSelectionPage disksPage; private List allDisks; private List selectedDisks; @@ -78,14 +75,12 @@ public class SelectDisksDialog extends Dialog { Composite container = new Composite(parent, SWT.NONE); GridLayout containerLayout = new GridLayout(2, false); container.setLayout(containerLayout); - GridData containerLayoutData = new GridData(SWT.FILL, SWT.FILL, true, - true); + GridData containerLayoutData = new GridData(SWT.FILL, SWT.FILL, true, true); container.setLayoutData(containerLayoutData); getShell().setText("Create Volume - Select Disks"); - disksPage = new CreateVolumeDisksPage(container, SWT.NONE, allDisks, - selectedDisks); + disksPage = new DisksSelectionPage(container, SWT.NONE, allDisks, selectedDisks); return container; } @@ -97,10 +92,8 @@ public class SelectDisksDialog extends Dialog { */ @Override protected void createButtonsForButtonBar(Composite parent) { - createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, - true); - createButton(parent, IDialogConstants.CANCEL_ID, - IDialogConstants.CANCEL_LABEL, false); + createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); + createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false); } /** @@ -112,15 +105,14 @@ public class SelectDisksDialog extends Dialog { } @Override - protected void cancelPressed() { + protected void cancelPressed() { System.out.println("Test"); super.cancelPressed(); } @Override protected void okPressed() { if (this.getSelectedDisks().size() == 0) { - MessageDialog.openError(getShell(), "Select Disk(s)", - "Please select atlease one disk"); + MessageDialog.openError(getShell(), "Select Disk(s)", "Please select atlease one disk"); } else { super.okPressed(); } @@ -129,7 +121,7 @@ public class SelectDisksDialog extends Dialog { public List getSelectedDisks() { return disksPage.getChosenDisks(); } - + public List getSelectedBricks() { return disksPage.getChosenBricks(); } diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/VolumesResource.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/VolumesResource.java index e30462f2..596ab62b 100644 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/VolumesResource.java +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/VolumesResource.java @@ -24,12 +24,14 @@ import static com.gluster.storage.management.core.constants.RESTConstants.FORM_P import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_VALUE_START; import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_VALUE_STOP; import static com.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_VOLUME_NAME; +import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_DELETE_OPTION; +import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_DISKS; import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_DISK_NAME; import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_LINE_COUNT; import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_VOLUME_NAME; -import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_DELETE_OPTION; import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_PATH_VOLUMES; import static com.gluster.storage.management.core.constants.RESTConstants.SUBRESOURCE_DEFAULT_OPTIONS; +import static com.gluster.storage.management.core.constants.RESTConstants.SUBRESOURCE_DISKS; import static com.gluster.storage.management.core.constants.RESTConstants.SUBRESOURCE_LOGS; import static com.gluster.storage.management.core.constants.RESTConstants.SUBRESOURCE_OPTIONS; @@ -218,17 +220,20 @@ public class VolumesResource { String[] diskParts = disk.split(":"); String serverName = diskParts[0]; String diskName = diskParts[1]; - - status = prepareBrick(serverName, diskName, volumeName); + try { + status = prepareBrick(serverName, diskName, volumeName); + } catch (Exception e) { + status = new Status(e); + } if (status.isSuccess()) { - String brickDir = status.getMessage().trim().replace(CoreConstants.NEWLINE, ""); + String brickDir = status.getMessage().trim(); bricks.add(serverName + ":" + brickDir); } else { // Brick preparation failed. Cleanup directories already created and return failure status Status cleanupStatus = cleanupDirectories(disks, volumeName, i + 1); if (!cleanupStatus.isSuccess()) { // append cleanup error to prepare brick error - status.setMessage(status.getMessage() + CoreConstants.NEWLINE + status.getMessage()); + status.setMessage(status.getMessage() + CoreConstants.NEWLINE + cleanupStatus.getMessage()); } return status; } @@ -237,6 +242,7 @@ public class VolumesResource { return status; } + //TODO Can be removed and use StringUtil.ListToString(List list, String delimiter) private String bricksAsString(List bricks) { String bricksStr = ""; for (String brickInfo : bricks) { @@ -245,6 +251,7 @@ public class VolumesResource { return bricksStr.trim(); } + @SuppressWarnings("rawtypes") private Status cleanupDirectories(List disks, String volumeName, int maxIndex) { String serverName, diskName, diskInfo[]; Status result; @@ -252,8 +259,8 @@ public class VolumesResource { diskInfo = disks.get(i).split(":"); serverName = diskInfo[0]; diskName = diskInfo[1]; - result = (Status) serverUtil.executeOnServer(true, serverName, VOLUME_DIRECTORY_CLEANUP_SCRIPT + " " - + diskName + " " + volumeName, Status.class); + result = ((GenericResponse) serverUtil.executeOnServer(true, serverName, VOLUME_DIRECTORY_CLEANUP_SCRIPT + " " + + diskName + " " + volumeName, GenericResponse.class)).getStatus(); if (!result.isSuccess()) { return result; } @@ -310,6 +317,26 @@ public class VolumesResource { return new LogMessageListResponse(Status.STATUS_SUCCESS, logMessages); } + + @POST + @Path("{" + QUERY_PARAM_VOLUME_NAME + "}/" + SUBRESOURCE_DISKS) + public Status addDisks(@PathParam(QUERY_PARAM_VOLUME_NAME) String volumeName, @FormParam(QUERY_PARAM_DISKS) String disks) { + + List diskList = Arrays.asList( disks.split(",") ); // Convert from comma separated sting (query parameter) to list + Status status = createDirectories(diskList, volumeName); + if (status.isSuccess()) { + List bricks = Arrays.asList(status.getMessage().split(" ")); + status = glusterUtil.addBricks(volumeName, bricks); + if (!status.isSuccess()) { + Status cleanupStatus = cleanupDirectories(diskList, volumeName, diskList.size()); + if (!cleanupStatus.isSuccess()) { + // append cleanup error to prepare brick error + status.setMessage(status.getMessage() + CoreConstants.NEWLINE + cleanupStatus.getMessage()); + } + } + } + return status; + } public static void main(String[] args) throws ClassNotFoundException { VolumesResource vr = new VolumesResource(); diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/GlusterUtil.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/GlusterUtil.java index 6a60962f..774deae1 100644 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/GlusterUtil.java +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/GlusterUtil.java @@ -48,11 +48,13 @@ public class GlusterUtil { private static final String VOLUME_NAME_PFX = "Volume Name:"; private static final String VOLUME_TYPE_PFX = "Type:"; private static final String VOLUME_STATUS_PFX = "Status:"; + private static final String VOLUME_NUMBER_OF_BRICKS = "Number of Bricks:"; private static final String VOLUME_TRANSPORT_TYPE_PFX = "Transport-type:"; private static final String VOLUME_BRICKS_GROUP_PFX = "Bricks"; private static final String VOLUME_OPTIONS_RECONFIG_PFX = "Options Reconfigured"; private static final String VOLUME_OPTION_AUTH_ALLOW = "auth.allow:"; - + private static final String VOLUME_TYPE_DISTRIBUTE = "Distribute"; + private static final String VOLUME_TYPE_REPLICATE = "Replicate"; private static final ProcessUtil processUtil = new ProcessUtil(); /** @@ -168,23 +170,22 @@ public class GlusterUtil { VOLUME_TYPE volType = volume.getVolumeType(); if (volType == VOLUME_TYPE.DISTRIBUTED_MIRROR) { volumeType = "replica"; - count = 2; + count = volume.getReplicaCount(); } else if (volType == VOLUME_TYPE.DISTRIBUTED_STRIPE) { volumeType = "stripe"; - count = 4; + count = volume.getStripeCount(); } String transportTypeStr = null; TRANSPORT_TYPE transportType = volume.getTransportType(); transportTypeStr = (transportType == TRANSPORT_TYPE.ETHERNET) ? "tcp" : "rdma"; - List command = prepareVolumeCreateCommand(volume, bricks, count, volumeType, transportTypeStr); ProcessResult result = processUtil.executeCommand(command); - if(!result.isSuccess()) { + if (!result.isSuccess()) { // TODO: Perform cleanup on all nodes before returning return new Status(result); } - + return createOptions(volume); } @@ -235,7 +236,7 @@ public class GlusterUtil { public Status deleteVolume(String volumeName) { return new Status(processUtil.executeCommand("gluster", "--mode=script", "volume", "delete", volumeName)); } - + private String getVolumeInfo(String volumeName) { ProcessResult result = new ProcessUtil().executeCommand("gluster", "volume", "info", volumeName); if (!result.isSuccess()) { @@ -253,17 +254,38 @@ public class GlusterUtil { } return result.getOutput(); } - + private boolean readVolumeType(Volume volume, String line) { String volumeType = extractToken(line, VOLUME_TYPE_PFX); if (volumeType != null) { - volume.setVolumeType((volumeType.equals("Distribute")) ? VOLUME_TYPE.PLAIN_DISTRIBUTE - : VOLUME_TYPE.DISTRIBUTED_MIRROR); // TODO: for Stripe + if (volumeType.equals(VOLUME_TYPE_DISTRIBUTE)) { + volume.setVolumeType(VOLUME_TYPE.PLAIN_DISTRIBUTE); + } else if (volumeType.equals(VOLUME_TYPE_REPLICATE)) { + volume.setVolumeType(VOLUME_TYPE.DISTRIBUTED_MIRROR); + volume.setReplicaCount(Volume.DEFAULT_REPLICA_COUNT); + } else { + volume.setVolumeType(VOLUME_TYPE.DISTRIBUTED_STRIPE); + volume.setStripeCount(Volume.DEFAULT_STRIPE_COUNT); + } return true; } return false; } - + + private void readReplicaOrStripeCount(Volume volume, String line) { + if (extractToken(line, "x") != null) { + // expected formated of line is "Number of Bricks: 3 x 2 = 6" + int count = Integer.parseInt(line.split("x")[1].split("=")[0].trim()); + if (volume.getVolumeType() == VOLUME_TYPE.DISTRIBUTED_STRIPE) { + volume.setStripeCount(count); + } else if (volume.getVolumeType() == VOLUME_TYPE.DISTRIBUTED_MIRROR) { + volume.setReplicaCount(count); + volume.setStripeCount(0); + } + } + return; + } + private boolean readVolumeStatus(Volume volume, String line) { String volumeStatus = extractToken(line, VOLUME_STATUS_PFX); if (volumeStatus != null) { @@ -272,17 +294,16 @@ public class GlusterUtil { } return false; } - + private boolean readTransportType(Volume volume, String line) { String transportType = extractToken(line, VOLUME_TRANSPORT_TYPE_PFX); if (transportType != null) { - volume.setTransportType(transportType.equals("tcp") ? TRANSPORT_TYPE.ETHERNET - : TRANSPORT_TYPE.INFINIBAND); + volume.setTransportType(transportType.equals("tcp") ? TRANSPORT_TYPE.ETHERNET : TRANSPORT_TYPE.INFINIBAND); return true; } return false; } - + private boolean readBrick(Volume volume, String line) { if (line.matches("Brick[0-9]+:.*")) { // line: "Brick1: server1:/export/md0/volume-name" @@ -292,11 +313,11 @@ public class GlusterUtil { // brick directory should be of the form /export//volume-name try { volume.addDisk(serverName + ":" + brickDir.split("/")[2].trim()); - } catch(ArrayIndexOutOfBoundsException e) { + } catch (ArrayIndexOutOfBoundsException e) { // brick directory of a different form, most probably created manually // connect to the server and get disk for the brick directory Status status = new ServerUtil().getDiskForDir(serverName, brickDir); - if(status.isSuccess()) { + if (status.isSuccess()) { volume.addDisk(serverName + ":" + status.getMessage()); } else { // Couldn't fetch disk for the brick directory. Log error and add "unknown" as disk name. @@ -308,15 +329,15 @@ public class GlusterUtil { } return false; } - + private boolean readBrickGroup(String line) { - return extractToken(line, VOLUME_BRICKS_GROUP_PFX) != null; + return extractToken(line, VOLUME_BRICKS_GROUP_PFX) != null; } - + private boolean readOptionReconfigGroup(String line) { return extractToken(line, VOLUME_OPTIONS_RECONFIG_PFX) != null; } - + private boolean readOption(Volume volume, String line) { if (line.matches("^[^:]*:.*$")) { int index = line.indexOf(':'); @@ -328,7 +349,7 @@ public class GlusterUtil { public Volume getVolume(String volumeName) { List volumes = parseVolumeInfo(getVolumeInfo(volumeName)); - if(volumes.size() > 0) { + if (volumes.size() > 0) { return volumes.get(0); } return null; @@ -348,7 +369,6 @@ public class GlusterUtil { String volumeName = extractToken(line, VOLUME_NAME_PFX); if (volumeName != null) { if (volume != null) { - volumes.add(volume); } @@ -361,11 +381,13 @@ public class GlusterUtil { if (readVolumeType(volume, line)) continue; + if (extractToken(line, VOLUME_NUMBER_OF_BRICKS) != null) { + readReplicaOrStripeCount(volume, line); + } if (readVolumeStatus(volume, line)) continue; - if(readTransportType(volume, line)) + if (readTransportType(volume, line)) continue; - if (readBrickGroup(line)) { isBricksGroupFound = true; continue; @@ -385,7 +407,7 @@ public class GlusterUtil { } if (isOptionReconfigFound) { - if(readOption(volume, line)) { + if (readOption(volume, line)) { continue; } else { isOptionReconfigFound = false; @@ -399,8 +421,23 @@ public class GlusterUtil { return volumes; } + public Status addBricks(String volumeName, List bricks) { + List command = new ArrayList(); + command.add("gluster"); + command.add("volume"); + command.add("add-brick"); + command.add(volumeName); + command.addAll(bricks); + return new Status(processUtil.executeCommand(command)); + } + public static void main(String args[]) { // List names = new GlusterUtil().getGlusterServerNames(); // System.out.println(names); + List disks = new ArrayList(); + disks.add("server1:sda"); + disks.add("server1:sdb"); + Status status = new GlusterUtil().addBricks("Volume3", disks); + System.out.println(status); } } -- cgit