diff options
| author | Shireesh Anjal <shireesh@gluster.com> | 2011-04-29 16:29:36 +0530 |
|---|---|---|
| committer | Shireesh Anjal <shireesh@gluster.com> | 2011-04-29 16:29:36 +0530 |
| commit | 9c749f036a5f6efd83b3d5fd8e90681916448db4 (patch) | |
| tree | 52c2854dc1f0e914c6b381f83456de3af31b566e /src | |
| parent | 9c566f1fa5efc95ab0c929d7f0615a3dad06bad0 (diff) | |
| parent | 1a2533deb10ed4dc0c4d910ce830a7065b845e68 (diff) | |
Merge branch 'master' of https://github.com/Selvasundaram/console into ss-master
Conflicts:
src/com.gluster.storage.management.gui/plugin.xml
Diffstat (limited to 'src')
14 files changed, 595 insertions, 81 deletions
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<String, String> 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 5cba6be8..87e02e28 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,14 +20,22 @@ */ package com.gluster.storage.management.client; + +import java.util.ArrayList; +import java.util.List; + import javax.ws.rs.core.MultivaluedMap; import com.gluster.storage.management.core.constants.RESTConstants; +import com.gluster.storage.management.core.model.Disk; +import com.gluster.storage.management.core.model.Disk.DISK_STATUS; import com.gluster.storage.management.core.model.Status; import com.gluster.storage.management.core.model.Volume; import com.gluster.storage.management.core.response.LogMessageListResponse; 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; import com.sun.jersey.core.util.MultivaluedMapImpl; @@ -45,14 +53,14 @@ public class VolumesClient extends AbstractClient { public Status createVolume(Volume volume) { return (Status) postObject(Status.class, volume); } - + private Status performOperation(String volumeName, String operation) { Form form = new Form(); form.add(RESTConstants.FORM_PARAM_OPERATION, operation); - - return (Status)putRequest(volumeName, Status.class, form); + + return (Status) putRequest(volumeName, Status.class, form); } - + public Status startVolume(String volumeName) { return performOperation(volumeName, RESTConstants.FORM_PARAM_VALUE_START); } @@ -60,26 +68,26 @@ public class VolumesClient extends AbstractClient { public Status stopVolume(String volumeName) { return performOperation(volumeName, RESTConstants.FORM_PARAM_VALUE_STOP); } - + public Status setVolumeOption(String volume, String key, String value) { Form form = new Form(); form.add(RESTConstants.FORM_PARAM_OPTION_KEY, key); form.add(RESTConstants.FORM_PARAM_OPTION_VALUE, value); - return (Status)postRequest(volume + "/" + RESTConstants.SUBRESOURCE_OPTIONS, Status.class, form); + return (Status) postRequest(volume + "/" + RESTConstants.SUBRESOURCE_OPTIONS, Status.class, form); } - + public Status resetVolumeOptions(String volume) { - return (Status)putRequest(volume + "/" + RESTConstants.SUBRESOURCE_OPTIONS, Status.class); + return (Status) putRequest(volume + "/" + RESTConstants.SUBRESOURCE_OPTIONS, Status.class); } - + public VolumeListResponse getAllVolumes() { return (VolumeListResponse) fetchResource(VolumeListResponse.class); } - + public Volume getVolume(String volumeName) { return (Volume) fetchSubResource(volumeName, Volume.class); } - + public Status deleteVolume(Volume volume, String deleteOption) { return (Status) deleteSubResource(volume.getName(), Status.class, volume.getName(), deleteOption); } @@ -89,12 +97,26 @@ public class VolumesClient extends AbstractClient { VolumeOptionInfoListResponse.class)); } + public Status addDisks(String volumeName, List<Disk> 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 Status addDisks(String volumeName, String disks) { + Form form = new Form(); + form.add(RESTConstants.QUERY_PARAM_DISKS, disks); + return (Status) postRequest(volumeName + "/" + RESTConstants.SUBRESOURCE_DISKS, Status.class, form); + } + public LogMessageListResponse getLogs(String volumeName, int lineCount) { MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl(); queryParams.add(RESTConstants.QUERY_PARAM_LINE_COUNT, "" + lineCount); // TODO: Add other filte criteria as query parameters return (LogMessageListResponse) fetchSubResource(volumeName + "/" + RESTConstants.SUBRESOURCE_LOGS, queryParams, LogMessageListResponse.class); + } public static void main(String[] args) { @@ -117,8 +139,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<Disk> disks = new ArrayList<Disk>(); + 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 83bdd166..41ed5a25 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", @@ -105,9 +109,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. <http://www.gluster.com> + * 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 + * <http://www.gnu.org/licenses/>. + */ +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<String> getQualifiedDiskNames(List<Disk> diskList) { + List<String> qualifiedDiskNames = new ArrayList<String>(); + 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<String> 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 2c9ea50d..b208fc24 100644 --- a/src/com.gluster.storage.management.gui/plugin.xml +++ b/src/com.gluster.storage.management.gui/plugin.xml @@ -257,6 +257,11 @@ id="com.gluster.storage.management.gui.commands.RemoveDisk" name="Remove Disk"> </command> + <command + description="Add Disk" + id="com.gluster.storage.management.gui.commands.AddDisk" + name="Add Disk"> + </command> </extension> <extension point="org.eclipse.ui.bindings"> @@ -497,11 +502,11 @@ style="push" toolbarPath="Normal" tooltip="Migrate Disk"> - <enablement> - <objectClass - name="com.gluster.storage.management.core.model.Disk"> - </objectClass> - </enablement> + <enablement> + <objectClass + name="com.gluster.storage.management.core.model.Disk"> + </objectClass> + </enablement> </action> <action allowLabelUpdate="false" @@ -597,7 +602,23 @@ state="false" style="push" toolbarPath="Normal" - tooltip="Remove Disk"> + tooltip="Remove Disk from Volume"> + </action> + <action + allowLabelUpdate="false" + class="com.gluster.storage.management.gui.actions.AddDiskAction" + definitionId="com.gluster.storage.management.gui.commands.AddDisk" + icon="icons/disk.png" + id="com.gluster.storage.management.gui.actions.AddDiskAction" + label="&Add Disk" + menubarPath="com.gluster.storage.management.gui.menu.volume/volume" + mode="FORCE_TEXT" + pulldown="false" + retarget="false" + state="false" + style="push" + toolbarPath="Normal" + tooltip="Add Disk to Volume"> </action> <menu id="com.gluster.storage.management.gui.menu.volume" diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/AddDiskAction.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/AddDiskAction.java new file mode 100644 index 00000000..cc57c541 --- /dev/null +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/AddDiskAction.java @@ -0,0 +1,84 @@ +/** + * AddDiskAction.java + * + * Copyright (c) 2011 Gluster, Inc. <http://www.gluster.com> + * 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 + * <http://www.gnu.org/licenses/>. + */ + +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.client.GlusterDataModelManager; +import com.gluster.storage.management.core.model.Volume; +import com.gluster.storage.management.gui.dialogs.AddDiskWizard; + +public class AddDiskAction extends AbstractActionDelegate { + private Volume volume; + private GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance(); + + /* (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..7eb107c0 --- /dev/null +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/AddDiskPage.java @@ -0,0 +1,165 @@ +/** + * AddDiskPage.java + * + * Copyright (c) 2011 Gluster, Inc. <http://www.gluster.com> + * 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 + * <http://www.gnu.org/licenses/>. + */ +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<Disk> availableDisks = new ArrayList<Disk>(); + private List<Disk> selectedDisks = new ArrayList<Disk>(); + 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<Disk> getAvailableDisks(Volume volume) { + List<Disk> availableDisks = new ArrayList<Disk>(); + for (Disk disk : GlusterDataModelManager.getInstance().getReadyDisksOfAllServers()) { + if ( ! isDiskUsed(volume, disk) ) { + availableDisks.add(disk); + } + } + return availableDisks; + } + + + public List<Disk> 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<Disk> chosenDisks = new ArrayList<Disk>(); // or volume.getDisks(); + + page = new DisksSelectionPage(parent, SWT.NONE, availableDisks, chosenDisks); + page.addDiskSelectionListener(new ListContentChangedListener<Disk>() { + @Override + public void listContentChanged(IRemovableContentProvider<Disk> contentProvider) { + List<Disk> 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..e9608e38 --- /dev/null +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/AddDiskWizard.java @@ -0,0 +1,92 @@ +/** + * AddDiskWizard.java + * + * Copyright (c) 2011 Gluster, Inc. <http://www.gluster.com> + * 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 + * <http://www.gnu.org/licenses/>. + */ +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<Disk> 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/DisksSelectionPage.java index c78601d9..e50e81a7 100644 --- 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/DisksSelectionPage.java @@ -19,7 +19,6 @@ 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; @@ -48,7 +47,7 @@ import com.richclientgui.toolbox.duallists.IRemovableContentProvider; import com.richclientgui.toolbox.duallists.RemovableContentProvider; import com.richclientgui.toolbox.duallists.TableColumnData; -public class CreateVolumeDisksPage extends Composite { +public class DisksSelectionPage extends Composite { private enum DISK_TABLE_COLUMN_INDICES { SERVER, DISK, SPACE, SPACE_USED } @@ -67,13 +66,17 @@ public class CreateVolumeDisksPage extends Composite { private Button btnDown; - public CreateVolumeDisksPage(final Composite parent, int style, List<Disk> allDisks, List<Disk> selectedDisks) { + public DisksSelectionPage(final Composite parent, int style, List<Disk> allDisks, List<Disk> selectedDisks) { super(parent, style); createPage(allDisks, selectedDisks); parent.layout(); } + + public void addDiskSelectionListener(ListContentChangedListener<Disk> listener) { + dualTableViewer.addChosenListChangedSelectionListener(listener); + } private TableLabelProviderAdapter getDiskLabelProvider() { return new TableLabelProviderAdapter() { 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 134323b3..08a35357 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<Disk> allDisks; private List<Disk> 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<Disk> getSelectedDisks() { return disksPage.getChosenDisks(); } - + public List<String> 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 11e12977..457776cc 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 @@ -25,11 +25,13 @@ import static com.gluster.storage.management.core.constants.RESTConstants.FORM_P 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.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<String> list, String delimiter) private String bricksAsString(List<String> bricks) { String bricksStr = ""; for (String brickInfo : bricks) { @@ -245,6 +251,7 @@ public class VolumesResource { return bricksStr.trim(); } + @SuppressWarnings("rawtypes") private Status cleanupDirectories(List<String> 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; } @@ -314,6 +321,27 @@ 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<String> diskList = Arrays.asList( disks.split(",") ); // Convert from comma separated sting (query parameter) to list + Status status = createDirectories(diskList, volumeName); + if (status.isSuccess()) { + List<String> 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; + } private String getBrickForDisk(Volume volume, String diskName) { int index = volume.getDisks().indexOf(diskName); 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 6e6e7e14..30f73595 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,12 +48,14 @@ 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_LOG_LOCATION_PFX = "log file location:"; - + private static final String VOLUME_TYPE_DISTRIBUTE = "Distribute"; + private static final String VOLUME_TYPE_REPLICATE = "Replicate"; private static final ProcessUtil processUtil = new ProcessUtil(); /** @@ -169,23 +171,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<String> 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); } @@ -236,7 +237,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()) { @@ -254,17 +255,40 @@ 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) { @@ -273,40 +297,40 @@ 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" String[] brickParts = line.split(":"); String serverName = brickParts[1].trim(); String brickDir = brickParts[2].trim(); - - volume.addBrick(serverName + ":" + brickDir); + + volume.addBrick(serverName + ":" + brickDir); detectAndAddDiskToVolume(volume, serverName, brickDir); return true; } return false; } + private void detectAndAddDiskToVolume(Volume volume, String serverName, String brickDir) { // brick directory should be of the form /export/<diskname>/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. @@ -315,15 +339,16 @@ public class GlusterUtil { } } } - + + 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(':'); @@ -335,7 +360,7 @@ public class GlusterUtil { public Volume getVolume(String volumeName) { List<Volume> volumes = parseVolumeInfo(getVolumeInfo(volumeName)); - if(volumes.size() > 0) { + if (volumes.size() > 0) { return volumes.get(0); } return null; @@ -355,7 +380,6 @@ public class GlusterUtil { String volumeName = extractToken(line, VOLUME_NAME_PFX); if (volumeName != null) { if (volume != null) { - volumes.add(volume); } @@ -368,11 +392,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; @@ -392,7 +418,7 @@ public class GlusterUtil { } if (isOptionReconfigFound) { - if(readOption(volume, line)) { + if (readOption(volume, line)) { continue; } else { isOptionReconfigFound = false; @@ -406,6 +432,18 @@ public class GlusterUtil { return volumes; } + + public Status addBricks(String volumeName, List<String> bricks) { + List<String> command = new ArrayList<String>(); + command.add("gluster"); + command.add("volume"); + command.add("add-brick"); + command.add(volumeName); + command.addAll(bricks); + return new Status(processUtil.executeCommand(command)); + } + + public String getLogLocation(String volumeName, String brickName) { ProcessResult result = new ProcessUtil().executeCommand("gluster", "volume", "log", "locate", volumeName, brickName); @@ -424,15 +462,21 @@ public class GlusterUtil { public String getLogFileNameForBrickDir(String brickDir) { String logFileName = brickDir; - if(logFileName.startsWith(CoreConstants.FILE_SEPARATOR)) { + if (logFileName.startsWith(CoreConstants.FILE_SEPARATOR)) { logFileName = logFileName.replaceFirst(CoreConstants.FILE_SEPARATOR, ""); } logFileName = logFileName.replaceAll(CoreConstants.FILE_SEPARATOR, "-") + ".log"; return logFileName; } + public static void main(String args[]) { // List<String> names = new GlusterUtil().getGlusterServerNames(); // System.out.println(names); + List<String> disks = new ArrayList<String>(); + disks.add("server1:sda"); + disks.add("server1:sdb"); + Status status = new GlusterUtil().addBricks("Volume3", disks); + System.out.println(status); } } |
