diff options
| author | Shireesh Anjal <shireesh@gluster.com> | 2011-04-07 21:38:32 +0530 |
|---|---|---|
| committer | Shireesh Anjal <shireesh@gluster.com> | 2011-04-07 21:38:32 +0530 |
| commit | f519a04fd95c7dba349a9a1b4275ef55e8e55990 (patch) | |
| tree | 5540b7c520473d418bf80c3bdc15c995ac7b7212 /src | |
| parent | 9461e6090694b777b9ac9ceae77de5e9e4df1b7d (diff) | |
Story#15 - Volume options
Diffstat (limited to 'src')
15 files changed, 413 insertions, 138 deletions
diff --git a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/AbstractClient.java b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/AbstractClient.java index 12fbd354..807e32a3 100644 --- a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/AbstractClient.java +++ b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/AbstractClient.java @@ -129,6 +129,17 @@ public abstract class AbstractClient { }
/**
+ * Submits given Form using PUT method to the given sub-resource and returns the object received as response
+ * @param subResourceName Name of the sub-resource to which the request is to be posted
+ * @param responseClass Class of the object expected as response
+ * @return Object of given class received as response
+ */
+ protected Object putRequest(String subResourceName, Class responseClass) {
+ return resource.path(subResourceName).type(MediaType.APPLICATION_FORM_URLENCODED_TYPE)
+ .header("Authorization", authHeader).accept(MediaType.TEXT_XML).put(responseClass);
+ }
+
+ /**
* Submits given object to the resource and returns the object received as response
* @param responseClass Class of the object expected as response
* @param requestObject the Object to be submitted
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 84074115..6a22bf5f 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 @@ -64,7 +64,7 @@ public class DiscoveredServersClient extends AbstractClient { public static void main(String[] args) { UsersClient usersClient = new UsersClient(); - if (usersClient.authenticate("gluster", "gluster")) { + if (usersClient.authenticate("gluster", "gluster").isSuccess()) { DiscoveredServersClient serverResource = new DiscoveredServersClient("localhost", usersClient.getSecurityToken()); List<String> discoveredServerNames = serverResource.getDiscoveredServerNames(); diff --git a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/GlusterServersClient.java b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/GlusterServersClient.java index dfee988c..8ae64016 100644 --- a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/GlusterServersClient.java +++ b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/GlusterServersClient.java @@ -63,7 +63,7 @@ public class GlusterServersClient extends AbstractClient { public static void main(String[] args) { UsersClient usersClient = new UsersClient(); - if (usersClient.authenticate("gluster", "gluster")) { + if (usersClient.authenticate("gluster", "gluster").isSuccess()) { GlusterServersClient serverResource = new GlusterServersClient(usersClient.getSecurityToken()); List<GlusterServer> glusterServers = serverResource.getServers(); diff --git a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/UsersClient.java b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/UsersClient.java index 8d7a52fc..0f2b5f86 100644 --- a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/UsersClient.java +++ b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/UsersClient.java @@ -19,6 +19,7 @@ package com.gluster.storage.management.client; import com.gluster.storage.management.core.model.Status; +import com.sun.jersey.api.client.UniformInterfaceException; import com.sun.jersey.api.representation.Form; import com.sun.jersey.core.util.Base64; @@ -26,6 +27,7 @@ public class UsersClient extends AbstractClient { private static final String RESOURCE_NAME = "users"; private static final String FORM_PARAM_OLD_PASSWORD = "oldpassword"; private static final String FORM_PARAM_NEW_PASSWORD = "newpassword"; + private static final int HTTP_STATUS_UNAUTHORIZED = 401; private String generateSecurityToken(String user, String password) { return new String(Base64.encode(user + ":" + password)); @@ -35,20 +37,26 @@ public class UsersClient extends AbstractClient { super(); } - public boolean authenticate(String user, String password) { + public Status authenticate(String user, String password) { setSecurityToken(generateSecurityToken(user, password)); try { Status authStatus = (Status) fetchSubResource(user, Status.class); - if (authStatus.isSuccess()) { - return true; + if(!authStatus.isSuccess()) { + // authentication failed. clear security token. + setSecurityToken(null); } + return authStatus; } catch (Exception e) { - e.printStackTrace(); + if (e instanceof UniformInterfaceException + && ((UniformInterfaceException) e).getResponse().getStatus() == HTTP_STATUS_UNAUTHORIZED) { + // authentication failed. clear security token. + setSecurityToken(null); + return new Status(Status.STATUS_CODE_FAILURE, "Invalid user id or password!"); + } else { + return new Status(Status.STATUS_CODE_FAILURE, "Exception during authentication: [" + e.getMessage() + + "]"); + } } - - // If we reach here, it means authentication failed. Clear security token and return false. - setSecurityToken(null); - return false; } public boolean changePassword(String user, String oldPassword, String newPassword) { 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 ab462abc..a479e1f7 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 @@ -26,7 +26,6 @@ import com.gluster.storage.management.core.constants.RESTConstants; import com.gluster.storage.management.core.model.Status; import com.gluster.storage.management.core.model.Volume; import com.gluster.storage.management.core.model.VolumeOptionInfo; -import com.gluster.storage.management.core.response.GenericResponse; import com.gluster.storage.management.core.response.VolumeListResponse; import com.gluster.storage.management.core.response.VolumeOptionInfoListResponse; import com.sun.jersey.api.representation.Form; @@ -42,14 +41,8 @@ public class VolumesClient extends AbstractClient { return RESTConstants.RESOURCE_PATH_VOLUMES; } - @SuppressWarnings("unchecked") public Status createVolume(Volume volume) { - GenericResponse<String> createVolumeResponse = (GenericResponse<String>) postObject(GenericResponse.class, volume); - - if (!createVolumeResponse.getStatus().isSuccess()) { - return (Status) createVolumeResponse.getStatus(); - } - return (Status) createVolumeResponse.getStatus(); + return (Status) postObject(Status.class, volume); } private Status performOperation(String volumeName, String operation) { @@ -67,11 +60,30 @@ public class VolumesClient extends AbstractClient { 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); + } + + public Status resetVolumeOptions(String volume) { + return (Status)putRequest(volume, Status.class); + } + public VolumeListResponse getAllVolumes() { return (VolumeListResponse) fetchResource(VolumeListResponse.class); } + + public Volume getVolume(String volumeName) { + return (Volume) fetchSubResource(volumeName, Volume.class); + } public List<VolumeOptionInfo> getVolumeOptionsDefaults() { + String responseStr = (String)fetchSubResource( + RESTConstants.SUBRESOURCE_DEFAULT_OPTIONS, String.class); + System.out.println(responseStr); + VolumeOptionInfoListResponse response = (VolumeOptionInfoListResponse) fetchSubResource( RESTConstants.SUBRESOURCE_DEFAULT_OPTIONS, VolumeOptionInfoListResponse.class); return response.getOptions(); @@ -79,7 +91,7 @@ public class VolumesClient extends AbstractClient { public static void main(String[] args) { UsersClient usersClient = new UsersClient(); - if (usersClient.authenticate("gluster", "gluster")) { + if (usersClient.authenticate("gluster", "gluster").isSuccess()) { VolumesClient client = new VolumesClient(usersClient.getSecurityToken()); // List<Disk> disks = new ArrayList<Disk>(); // Disk diskElement = new Disk(); @@ -94,9 +106,11 @@ public class VolumesClient extends AbstractClient { // Volume.VOLUME_STATUS.ONLINE); // // vol.setDisks(disks); // System.out.println(client.createVolume(vol)); - for (VolumeOptionInfo option : client.getVolumeOptionsDefaults()) { - System.out.println(option.getName() + "-" + option.getDescription() + "-" + option.getDefaultValue()); - } +// 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()); } } } 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 47697eb9..b5b51cfd 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,8 +29,11 @@ public class RESTConstants { public static final String FORM_PARAM_OPERATION = "operation"; public static final String FORM_PARAM_VALUE_START = "start"; public static final String FORM_PARAM_VALUE_STOP = "stop"; + public static final String FORM_PARAM_OPTION_KEY = "key"; + public static final String FORM_PARAM_OPTION_VALUE = "value"; public static final String PATH_PARAM_VOLUME_NAME = "volumeName"; public static final String SUBRESOURCE_DEFAULT_OPTIONS = "defaultoptions"; + public static final String SUBRESOURCE_OPTIONS = "options"; // Running tasks resource public static final String RESOURCE_PATH_RUNNING_TASKS = "/cluster/runningtasks"; 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 968611ec..baa3edb9 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 @@ -174,12 +174,13 @@ public class Volume extends Entity { return protocolsStr; } + @XmlTransient public String getAccessControlList() { return options.get(OPTION_AUTH_ALLOW); } public void setAccessControlList(String accessControlList) { - this.accessControlList = accessControlList; + setOption(OPTION_AUTH_ALLOW, accessControlList); } public Map<String, String> getOptions() { diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/GlusterUtil.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/GlusterUtil.java index 300f79ef..35bba55d 100644 --- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/GlusterUtil.java +++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/GlusterUtil.java @@ -22,18 +22,21 @@ package com.gluster.storage.management.core.utils; import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; import com.gluster.storage.management.core.constants.CoreConstants; import com.gluster.storage.management.core.exceptions.GlusterRuntimeException; -import com.gluster.storage.management.core.model.Disk; import com.gluster.storage.management.core.model.GlusterServer; import com.gluster.storage.management.core.model.GlusterServer.SERVER_STATUS; +import com.gluster.storage.management.core.model.Status; import com.gluster.storage.management.core.model.Volume; import com.gluster.storage.management.core.model.Volume.TRANSPORT_TYPE; import com.gluster.storage.management.core.model.Volume.VOLUME_STATUS; import com.gluster.storage.management.core.model.Volume.VOLUME_TYPE; public class GlusterUtil { + private static final String glusterFSminVersion = "3.1"; private static final String HOSTNAME_PFX = "Hostname:"; private static final String UUID_PFX = "Uuid:"; @@ -140,19 +143,23 @@ public class GlusterUtil { return output; } - public ProcessResult addServer(String serverName) { - return processUtil.executeCommand("gluster", "peer", "probe", serverName); + public Status addServer(String serverName) { + return new Status(processUtil.executeCommand("gluster", "peer", "probe", serverName)); } - public ProcessResult startVolume(String volumeName) { - return processUtil.executeCommand("gluster", "volume", "start", volumeName); + public Status startVolume(String volumeName) { + return new Status(processUtil.executeCommand("gluster", "volume", "start", volumeName)); } - public ProcessResult stopVolume(String volumeName) { - return processUtil.executeCommand("gluster", "--mode=script", "volume", "stop", volumeName); + public Status stopVolume(String volumeName) { + return new Status(processUtil.executeCommand("gluster", "--mode=script", "volume", "stop", volumeName)); } - public ProcessResult createVolume(Volume volume, List<String> bricks) { + public Status resetOptions(String volumeName) { + return new Status(processUtil.executeCommand("gluster", "volume", "reset", volumeName)); + } + + public Status createVolume(Volume volume, List<String> bricks) { int count = 1; // replica or stripe count String volumeType = null; VOLUME_TYPE volType = volume.getVolumeType(); @@ -168,6 +175,18 @@ public class GlusterUtil { 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()) { + // TODO: Perform cleanup on all nodes before returning + return new Status(result); + } + + return createOptions(volume); + } + + private List<String> prepareVolumeCreateCommand(Volume volume, List<String> bricks, int count, String volumeType, + String transportTypeStr) { List<String> command = new ArrayList<String>(); command.add("gluster"); command.add("volume"); @@ -180,22 +199,43 @@ public class GlusterUtil { command.add("transport"); command.add(transportTypeStr); command.addAll(bricks); - return processUtil.executeCommand(command); + return command; } - public ProcessResult setOption(List<String> command) { - return processUtil.executeCommand(command); + private Status createOptions(Volume volume) { + Map<String, String> options = volume.getOptions(); + if (options != null) { + for (Entry<String, String> option : options.entrySet()) { + String key = option.getKey(); + String value = option.getValue(); + Status status = setOption(volume.getName(), key, value); + if (!status.isSuccess()) { + return status; + } + } + } + return Status.STATUS_SUCCESS; } - public ProcessResult setVolumeAccessControl(Volume volume) { + public Status setOption(String volumeName, String key, String value) { List<String> command = new ArrayList<String>(); command.add("gluster"); command.add("volume"); command.add("set"); - command.add(volume.getName()); - command.add("auth.allow"); - command.add(volume.getAccessControlList()); - return setOption(command); + command.add(volumeName); + command.add(key); + command.add(value); + + return new Status(processUtil.executeCommand(command)); + } + + private String getVolumeInfo(String volumeName) { + ProcessResult result = new ProcessUtil().executeCommand("gluster", "volume", "info", volumeName); + if (!result.isSuccess()) { + throw new GlusterRuntimeException("Command [gluster volume info] failed with error: [" + + result.getExitValue() + "][" + result.getOutput() + "]"); + } + return result.getOutput(); } private String getVolumeInfo() { @@ -206,10 +246,75 @@ 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 + return true; + } + return false; + } + + private boolean readVolumeStatus(Volume volume, String line) { + String volumeStatus = extractToken(line, VOLUME_STATUS_PFX); + if (volumeStatus != null) { + volume.setStatus(volumeStatus.equals("Started") ? VOLUME_STATUS.ONLINE : VOLUME_STATUS.OFFLINE); + return true; + } + 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); + return true; + } + return false; + } + + private boolean readBrick(Volume volume, String line) { + if (line.matches("Brick[0-9]+:.*")) { + // line: "Brick1: server1:/export/md0/volume-name" + volume.addDisk(line.split(":")[2].trim().split("/")[2].trim()); + return true; + } + return false; + } + + private boolean readBrickGroup(String line) { + 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("^[^:]*:[^:]*$")) { + String[] parts = line.split(":"); + volume.setOption(parts[0].trim(), parts[1].trim()); + return true; + } + return false; + } + + public Volume getVolume(String volumeName) { + List<Volume> volumes = parseVolumeInfo(getVolumeInfo(volumeName)); + if(volumes.size() > 0) { + return volumes.get(0); + } + return null; + } public List<Volume> getAllVolumes() { - String volumeInfoText = getVolumeInfo(); + return parseVolumeInfo(getVolumeInfo()); + } + private List<Volume> parseVolumeInfo(String volumeInfoText) { List<Volume> volumes = new ArrayList<Volume>(); boolean isBricksGroupFound = false; boolean isOptionReconfigFound = false; @@ -230,50 +335,34 @@ public class GlusterUtil { continue; } - String volumeType = extractToken(line, VOLUME_TYPE_PFX); - if (volumeType != null) { - volume.setVolumeType((volumeType == "Distribute") ? VOLUME_TYPE.PLAIN_DISTRIBUTE - : VOLUME_TYPE.DISTRIBUTED_MIRROR); // TODO: for Stripe + if (readVolumeType(volume, line)) continue; - } - - String volumeStatus = extractToken(line, VOLUME_STATUS_PFX); - if (volumeStatus != null) { - volume.setStatus(volumeStatus.equals("Started") ? VOLUME_STATUS.ONLINE : VOLUME_STATUS.OFFLINE); + if (readVolumeStatus(volume, line)) continue; - } - - String transportType = extractToken(line, VOLUME_TRANSPORT_TYPE_PFX); - if (transportType != null) { - volume.setTransportType(transportType.equals("tcp") ? TRANSPORT_TYPE.ETHERNET - : TRANSPORT_TYPE.INFINIBAND); + if(readTransportType(volume, line)) continue; - } - - if (extractToken(line, VOLUME_BRICKS_GROUP_PFX) != null) { + + if (readBrickGroup(line)) { isBricksGroupFound = true; continue; } if (isBricksGroupFound) { - if (line.matches("Brick[0-9]+:.*")) { - // line: "Brick1: server1:/export/md0/volume-name" - volume.addDisk(line.split(":")[2].trim().split("/")[2].trim()); + if (readBrick(volume, line)) { continue; } else { isBricksGroupFound = false; } } - if (extractToken(line, VOLUME_OPTIONS_RECONFIG_PFX) != null) { + if (readOptionReconfigGroup(line)) { isOptionReconfigFound = true; continue; } if (isOptionReconfigFound) { - if (line.matches("^[^:]*:[^:]*$")) { - String[] parts = line.split(":"); - volume.setOption(parts[0].trim(), parts[1].trim()); + if(readOption(volume, line)) { + continue; } else { isOptionReconfigFound = false; } diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/login/LoginDialog.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/login/LoginDialog.java index a1be243d..30406e27 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/login/LoginDialog.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/login/LoginDialog.java @@ -193,7 +193,7 @@ public class LoginDialog extends Dialog { String password = connectionDetails.getPassword(); UsersClient usersClient = new UsersClient(); - if (usersClient.authenticate(user, password)) { + if (usersClient.authenticate(user, password).isSuccess()) { try { GlusterDataModelManager.getInstance().initializeModel(usersClient.getSecurityToken()); super.okPressed(); diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/GUIHelper.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/GUIHelper.java index ccd5d8ec..9f5fdfb7 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/GUIHelper.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/GUIHelper.java @@ -36,7 +36,6 @@ import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.StructuredViewer; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TableViewerColumn; -import org.eclipse.jface.viewers.TreeSelection; import org.eclipse.swt.SWT; import org.eclipse.swt.events.KeyAdapter; import org.eclipse.swt.events.KeyEvent; @@ -57,6 +56,7 @@ import org.eclipse.swt.widgets.Text; import org.eclipse.ui.IViewPart; import org.eclipse.ui.IViewReference; import org.eclipse.ui.IWorkbenchSite; +import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.forms.events.ExpansionAdapter; import org.eclipse.ui.forms.events.ExpansionEvent; @@ -64,9 +64,9 @@ import org.eclipse.ui.forms.widgets.ColumnLayout; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.ScrolledForm; import org.eclipse.ui.forms.widgets.Section; +import org.eclipse.ui.progress.IProgressConstants; -import com.gluster.storage.management.core.model.Entity; -import com.gluster.storage.management.core.model.EntityGroup; +import com.gluster.storage.management.core.exceptions.GlusterRuntimeException; import com.gluster.storage.management.gui.IImageKeys; import com.gluster.storage.management.gui.views.NavigationView; @@ -360,4 +360,14 @@ public class GUIHelper { } return null; } + + public void showProgressView() { + try { + PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage() + .showView(IProgressConstants.PROGRESS_VIEW_ID); + } catch (PartInitException e) { + e.printStackTrace(); + throw new GlusterRuntimeException("Could not open the progress view!", e); + } + } } diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/AbstractDisksPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/AbstractDisksPage.java index e00fe3f8..593f7ba1 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/AbstractDisksPage.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/AbstractDisksPage.java @@ -276,13 +276,7 @@ public abstract class AbstractDisksPage extends Composite implements IEntityList @Override public void linkActivated(HyperlinkEvent e) { updateStatus(DISK_STATUS.INITIALIZING, true); - - try { - site.getWorkbenchWindow().getActivePage().showView(IProgressConstants.PROGRESS_VIEW_ID); - } catch (PartInitException e1) { - e1.printStackTrace(); - throw new GlusterRuntimeException("Could not open the progress view!", e1); - } + guiHelper.showProgressView(); new InitializeDiskJob(disk).schedule(); } diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/VolumeOptionsPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/VolumeOptionsPage.java index baa14a59..cd425dc2 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/VolumeOptionsPage.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/VolumeOptionsPage.java @@ -18,16 +18,28 @@ *******************************************************************************/ package com.gluster.storage.management.gui.views.details; +import java.util.Map.Entry; + +import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.layout.TableColumnLayout; import org.eclipse.jface.viewers.ArrayContentProvider; +import org.eclipse.jface.viewers.CellEditor; import org.eclipse.jface.viewers.CheckboxTableViewer; +import org.eclipse.jface.viewers.ColumnLabelProvider; +import org.eclipse.jface.viewers.ColumnLayoutData; +import org.eclipse.jface.viewers.ColumnViewer; import org.eclipse.jface.viewers.ColumnWeightData; +import org.eclipse.jface.viewers.EditingSupport; import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.TableViewerColumn; +import org.eclipse.jface.viewers.TextCellEditor; import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.BusyIndicator; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; +import org.eclipse.swt.graphics.Cursor; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; @@ -38,6 +50,9 @@ import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.forms.widgets.FormToolkit; +import com.gluster.storage.management.client.GlusterDataModelManager; +import com.gluster.storage.management.client.VolumesClient; +import com.gluster.storage.management.core.model.Status; import com.gluster.storage.management.core.model.Volume; import com.gluster.storage.management.gui.VolumeOptionsTableLabelProvider; import com.gluster.storage.management.gui.utils.GUIHelper; @@ -47,6 +62,7 @@ public class VolumeOptionsPage extends Composite { private final FormToolkit toolkit = new FormToolkit(Display.getCurrent()); private TableViewer tableViewer; private GUIHelper guiHelper = GUIHelper.getInstance(); + private Volume volume; public enum OPTIONS_TABLE_COLUMN_INDICES { OPTION_KEY, OPTION_VALUE @@ -72,6 +88,7 @@ public class VolumeOptionsPage extends Composite { public VolumeOptionsPage(final Composite parent, int style, Volume volume) { this(parent, style); + this.volume = volume; tableViewer.setInput(volume.getOptions().entrySet().toArray()); @@ -98,26 +115,117 @@ public class VolumeOptionsPage extends Composite { setLayout(layout); } - private void setupDiskTable(Composite parent, Table table) { + private void setupDiskTable(Composite parent) { + Table table = tableViewer.getTable(); table.setHeaderVisible(true); table.setLinesVisible(false); - TableColumnLayout tableColumnLayout = guiHelper.createTableColumnLayout(table, OPTIONS_TABLE_COLUMN_NAMES); + TableColumnLayout tableColumnLayout = createTableColumnLayout(); parent.setLayout(tableColumnLayout); setColumnProperties(table, OPTIONS_TABLE_COLUMN_INDICES.OPTION_KEY, SWT.CENTER, 100); setColumnProperties(table, OPTIONS_TABLE_COLUMN_INDICES.OPTION_VALUE, SWT.CENTER, 100); } + + private TableColumnLayout createTableColumnLayout() { + TableColumnLayout tableColumnLayout = new TableColumnLayout(); + ColumnLayoutData defaultColumnLayoutData = new ColumnWeightData(100); + + tableColumnLayout.setColumnData(createKeyColumn(), defaultColumnLayoutData); + tableColumnLayout.setColumnData(createValueColumn(), defaultColumnLayoutData); + + return tableColumnLayout; + } + + private class OptionValueEditingSupport extends EditingSupport { + private CellEditor cellEditor; + + public OptionValueEditingSupport(ColumnViewer viewer) { + super(viewer); + cellEditor = new TextCellEditor((Composite) viewer.getControl()); + } + + @Override + protected void setValue(final Object element, final Object value) { + final Entry<String, String> entry = (Entry<String, String>)element; + if(entry.getValue().equals(value)) { + // value is same as that present in the model. return without doing anything. + return; + } + + final Cursor oldCursor = getViewer().getControl().getCursor(); + //getViewer().getControl().setCursor(new Cursor(Display.getDefault(), SWT.CURSOR_WAIT)); + // value has changed. set volume option at back-end and update model accordingly + BusyIndicator.showWhile(getDisplay(), new Runnable() { + + @Override + public void run() { + VolumesClient client = new VolumesClient(GlusterDataModelManager.getInstance().getSecurityToken()); + Status status = client.setVolumeOption(volume.getName(), entry.getKey(), (String)value); + if(status.isSuccess()) { + volume.setOption(entry.getKey(), (String)value); + } else { + MessageDialog.openError(getShell(), "Set Volume Option", status.getMessage()); + } + getViewer().update(entry, null); + //getViewer().refresh(); + //getViewer().getControl().setCursor(oldCursor); + } + }); + } + + @Override + protected Object getValue(Object element) { + return ((Entry<String, String>) element).getValue(); + } + + @Override + protected CellEditor getCellEditor(Object element) { + return cellEditor; + } + + @Override + protected boolean canEdit(Object element) { + return true; + } + } + + private TableColumn createValueColumn() { + TableViewerColumn valueColumn = new TableViewerColumn(tableViewer, SWT.NONE); + valueColumn.getColumn() + .setText(OPTIONS_TABLE_COLUMN_NAMES[OPTIONS_TABLE_COLUMN_INDICES.OPTION_VALUE.ordinal()]); + valueColumn.setLabelProvider(new ColumnLabelProvider() { + @Override + public String getText(Object element) { + return ((Entry<String, String>) element).getValue(); + } + }); + + // User can edit value of a volume option + valueColumn.setEditingSupport(new OptionValueEditingSupport(valueColumn.getViewer())); + + return valueColumn.getColumn(); + } - private TableViewer createDiskTableViewer(Composite parent) { - TableViewer tableViewer = CheckboxTableViewer.newCheckList(parent, SWT.FLAT | SWT.FULL_SELECTION | SWT.MULTI); + private TableColumn createKeyColumn() { + TableViewerColumn keyColumn = new TableViewerColumn(tableViewer, SWT.NONE); + keyColumn.getColumn().setText(OPTIONS_TABLE_COLUMN_NAMES[OPTIONS_TABLE_COLUMN_INDICES.OPTION_KEY.ordinal()]); + keyColumn.setLabelProvider(new ColumnLabelProvider() { + @Override + public String getText(Object element) { + return ((Entry<String, String>) element).getKey(); + } + }); + return keyColumn.getColumn(); + } + + private void createDiskTableViewer(Composite parent) { + tableViewer = CheckboxTableViewer.newCheckList(parent, SWT.FLAT | SWT.FULL_SELECTION | SWT.MULTI); // TableViewer tableViewer = new TableViewer(parent, SWT.FLAT | SWT.FULL_SELECTION | SWT.MULTI); tableViewer.setLabelProvider(new VolumeOptionsTableLabelProvider()); tableViewer.setContentProvider(new ArrayContentProvider()); - setupDiskTable(parent, tableViewer.getTable()); - - return tableViewer; + setupDiskTable(parent); } private Composite createTableViewerComposite() { @@ -129,7 +237,7 @@ public class VolumeOptionsPage extends Composite { private void setupDiskTableViewer(final Text filterText) { Composite tableViewerComposite = createTableViewerComposite(); - tableViewer = createDiskTableViewer(tableViewerComposite); + createDiskTableViewer(tableViewerComposite); // Create a case insensitive filter for the table viewer using the filter text field guiHelper.createFilter(tableViewer, filterText, false); } diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/GlusterServersResource.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/GlusterServersResource.java index e8adceb7..42f7760e 100644 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/GlusterServersResource.java +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/GlusterServersResource.java @@ -94,12 +94,10 @@ public class GlusterServersResource extends AbstractServersResource { @POST @Produces(MediaType.TEXT_XML) public GlusterServerResponse addServer(@FormParam("serverName") String serverName) { - ProcessResult result = glusterUtil.addServer(serverName); + Status status = glusterUtil.addServer(serverName); - if (!result.isSuccess()) { - Status failure = new Status(Status.STATUS_CODE_FAILURE, "Add server [" + serverName + "] failed: [" + result.getExitValue() - + "][" + result.getOutput() + "]"); - return new GlusterServerResponse(failure, null); + if (!status.isSuccess()) { + return new GlusterServerResponse(status, null); } return new GlusterServerResponse(Status.STATUS_SUCCESS, getGlusterServer(serverName)); } 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 22ef2462..49fb1e0d 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 @@ -26,6 +26,7 @@ import static com.gluster.storage.management.core.constants.RESTConstants.FORM_P import static com.gluster.storage.management.core.constants.RESTConstants.PATH_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_OPTIONS; import java.util.ArrayList; import java.util.List; @@ -40,15 +41,12 @@ import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; -import org.springframework.beans.factory.annotation.Autowired; - +import com.gluster.storage.management.core.constants.RESTConstants; import com.gluster.storage.management.core.model.Status; import com.gluster.storage.management.core.model.Volume; -import com.gluster.storage.management.core.response.GenericResponse; import com.gluster.storage.management.core.response.VolumeListResponse; import com.gluster.storage.management.core.response.VolumeOptionInfoListResponse; import com.gluster.storage.management.core.utils.GlusterUtil; -import com.gluster.storage.management.core.utils.ProcessResult; import com.gluster.storage.management.server.constants.VolumeOptionsDefaults; import com.gluster.storage.management.server.utils.ServerUtil; import com.sun.jersey.api.core.InjectParam; @@ -57,9 +55,9 @@ import com.sun.jersey.spi.resource.Singleton; @Singleton @Path(RESOURCE_PATH_VOLUMES) public class VolumesResource { - private static final String SCRIPT_NAME = "CreateVolumeExportDirectory.py"; + private static final String SCRIPT_NAME = "preVolumeCreate.py"; - @Autowired + @InjectParam private static ServerUtil serverUtil; private final GlusterUtil glusterUtil = new GlusterUtil(); @@ -80,30 +78,34 @@ public class VolumesResource { @POST @Consumes(MediaType.TEXT_XML) @Produces(MediaType.TEXT_XML) - public GenericResponse<String> createVolume(Volume volume) { + public Status createVolume(Volume volume) { //Create the directories for the volume List<String> bricks = new ArrayList<String>(); for(String disk : volume.getDisks()) { - String brickNotation = getBrickNotation(volume, disk); + String brickNotation = prepareBrick(volume, disk); if (brickNotation != null) { bricks.add(brickNotation); } else { - return new GenericResponse<String>(Status.STATUS_FAILURE, "Disk is not mounted properly. Pls mount the disk."); + int failedIndex = volume.getDisks().indexOf(disk); + // TODO: Perform cleanup on all previously prepared bricks + // i.e. those disks with index < failedIndex + + return new Status(Status.STATUS_CODE_FAILURE, "Error while preparing disk [" + disk + "] for volume [" + + volume.getName() + "]"); } } - ProcessResult response = glusterUtil.createVolume(volume, bricks); - if (!response.isSuccess()) { - return new GenericResponse<String>(Status.STATUS_FAILURE, "Volume creation failed: [" - + response.getOutput() + "]"); - } - - response = glusterUtil.setVolumeAccessControl(volume); - - return new GenericResponse<String>(Status.STATUS_SUCCESS, response.getOutput()); + return glusterUtil.createVolume(volume, bricks); } + @GET + @Path("{" + PATH_PARAM_VOLUME_NAME + "}") + @Produces(MediaType.TEXT_XML) + public Volume getVolume(@PathParam(PATH_PARAM_VOLUME_NAME) String volumeName) { + return glusterUtil.getVolume(volumeName); + } + @PUT @Path("{" + PATH_PARAM_VOLUME_NAME + "}") @Produces(MediaType.TEXT_XML) @@ -111,40 +113,57 @@ public class VolumesResource { @PathParam(PATH_PARAM_VOLUME_NAME) String volumeName) { if (operation.equals(FORM_PARAM_VALUE_START)) { - return new Status(glusterUtil.startVolume(volumeName)); + return glusterUtil.startVolume(volumeName); } if (operation.equals(FORM_PARAM_VALUE_STOP)) { - return new Status(glusterUtil.stopVolume(volumeName)); + return glusterUtil.stopVolume(volumeName); } return new Status(Status.STATUS_CODE_FAILURE, "Invalid operation code [" + operation + "]"); } + @POST + @Path("{" + PATH_PARAM_VOLUME_NAME + " }/" + SUBRESOURCE_OPTIONS) + @Produces(MediaType.TEXT_XML) + public Status setOption(@PathParam(PATH_PARAM_VOLUME_NAME) String volumeName, + @FormParam(RESTConstants.FORM_PARAM_OPTION_KEY) String key, + @FormParam(RESTConstants.FORM_PARAM_OPTION_VALUE) String value) { + return glusterUtil.setOption(volumeName, key, value); + } + + @PUT + @Path("{" + PATH_PARAM_VOLUME_NAME + " }/" + SUBRESOURCE_OPTIONS) + @Produces(MediaType.TEXT_XML) + public Status resetOptions(@PathParam(PATH_PARAM_VOLUME_NAME) String volumeName) { + return glusterUtil.resetOptions(volumeName); + } + @GET @Path(SUBRESOURCE_DEFAULT_OPTIONS) @Produces(MediaType.TEXT_XML) public VolumeOptionInfoListResponse getDefaultOptions() { - // TODO: Fetch all volume options with their default values from - // GlusterFS + // TODO: Fetch all volume options with their default values from GlusterFS // whenever such a CLI command is made available in GlusterFS return new VolumeOptionInfoListResponse(Status.STATUS_SUCCESS, volumeOptionsDefaults.getDefaults()); } - private String getBrickNotation(Volume vol, String disk) { + private String prepareBrick(Volume vol, String disk) { String serverName = disk.split(":")[0]; - String exportDirectory = disk.split(":")[1]; - Status result = serverUtil.executeOnServer(true, serverName, "python " + SCRIPT_NAME +" " + exportDirectory + " " + vol.getName()); + String diskName = disk.split(":")[1]; + Status result = (Status)serverUtil.executeOnServer(true, serverName, SCRIPT_NAME + " " + vol.getName() + " " + diskName, Status.class); - if(result.getCode() == 0) { - String dirName = "/export/" + disk + "/" + vol.getName() ; - return serverName + ":" + dirName; + if(result.isSuccess()) { + return result.getMessage(); } else { return null; } - } - public static void main(String args[]) { - // Disk disk = null; - serverUtil.executeOnServer(true, "localhost", "CreateVolumeExportDirectory.py md0 testvol"); + public static void main(String[] args) { + VolumesResource vr = new VolumesResource(); + VolumeListResponse response = vr.getAllVolumes(); + for (Volume volume : response.getVolumes()) { + System.out.println("\nName:" + volume.getName() + "\nType: " + volume.getVolumeTypeStr() + "\nStatus: " + + volume.getStatusStr()); + } } -}
\ No newline at end of file +} diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/ServerUtil.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/ServerUtil.java index b2264ffa..645b7991 100644 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/ServerUtil.java +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/ServerUtil.java @@ -22,7 +22,6 @@ package com.gluster.storage.management.server.utils; import java.io.BufferedReader; import java.io.ByteArrayInputStream; -import java.io.FileReader; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.InetAddress; @@ -32,7 +31,7 @@ import java.util.List; import javax.servlet.ServletContext; import javax.xml.bind.JAXBContext; -import javax.xml.bind.Marshaller; +import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; import org.springframework.beans.factory.annotation.Autowired; @@ -42,9 +41,7 @@ import com.gluster.storage.management.core.constants.CoreConstants; import com.gluster.storage.management.core.model.Status; import com.gluster.storage.management.core.utils.ProcessResult; import com.gluster.storage.management.core.utils.ProcessUtil; -import com.sun.jersey.spi.resource.Singleton; -@Singleton @Component public class ServerUtil { @Autowired @@ -73,9 +70,11 @@ public class ServerUtil { * @param runInForeground * @param serverName * @param commandWithArgs + * @param expectedClass Class of the object expected from script execution * @return Response from remote execution of the command */ - public Status executeOnServer(boolean runInForeground, String serverName, String commandWithArgs) { + public Object executeOnServer(boolean runInForeground, String serverName, String commandWithArgs, Class expectedClass) { + StringBuffer output = new StringBuffer(); try { InetAddress address = InetAddress.getByName(serverName); Socket connection = new Socket(address, 50000); @@ -86,7 +85,6 @@ public class ServerUtil { writer.println(commandWithArgs); writer.println(); // empty line means end of request - StringBuffer output = new StringBuffer(); String line; while (!(line = reader.readLine()).trim().isEmpty()) { output.append(line + CoreConstants.NEWLINE); @@ -94,23 +92,45 @@ public class ServerUtil { connection.close(); System.out.println("The ouput string is : " + output.toString()); - // create JAXB context and instantiate marshaller - JAXBContext context = JAXBContext.newInstance(Status.class); - Unmarshaller um = context.createUnmarshaller(); - Status result = (Status) um.unmarshal(new ByteArrayInputStream(output.toString().getBytes())); + return unmarshal(expectedClass, output.toString(), expectedClass != Status.class); + } catch(Exception e) { + // any other exception means unexpected error. return status with error from exception. + return new Status(Status.STATUS_CODE_FAILURE, "Error during remote execution: [" + e.getMessage() + "]"); + } + } - return result; + /** + * Unmarshals given input string into object of given class + * + * @param expectedClass + * Class whose object is expected + * @param input + * Input string + * @param tryStatusOnFailure + * If true, and if the unmarshalling fails for given class, another unmarshalling will be attempted with + * class Status. If that also fails, a status object with exception message is created and returned. + * @return Object of given expected class, or a status object in case first unmarshalling fails. + */ + private Object unmarshal(Class expectedClass, String input, boolean tryStatusOnFailure) { + try { + // create JAXB context and instantiate marshaller + JAXBContext context = JAXBContext.newInstance(expectedClass); + Unmarshaller um = context.createUnmarshaller(); + return um.unmarshal(new ByteArrayInputStream(input.getBytes())); + } catch (JAXBException e) { + if(tryStatusOnFailure) { + // unmarshalling failed. try to unmarshal a Status object + return unmarshal(Status.class, input, false); + } - // return new ProcessResult( 0, output.toString()); - } catch (Exception e) { - e.printStackTrace(); + return new Status(Status.STATUS_CODE_FAILURE, "Error during unmarshalling string [" + input + + "] for class [" + expectedClass.getName() + ": [" + e.getMessage() + "]"); } - return null; } public static void main(String args[]) { // CreateVolumeExportDirectory.py md0 testvol - System.out.println(new ServerUtil().executeOnServer(true, "localhost", "python CreateVolumeExportDirectory.py md0 testvol").getMessage()); + System.out.println(new ServerUtil().executeOnServer(true, "localhost", "python CreateVolumeExportDirectory.py md0 testvol", Status.class)); } }
\ No newline at end of file |
