From b51fce37009145f91f0345b428eb297ad4691563 Mon Sep 17 00:00:00 2001 From: Dhandapani Date: Mon, 27 Jun 2011 16:21:16 +0530 Subject: Story #1: Rebalance Volume --- .../storage/management/client/VolumesClient.java | 9 ++ .../management/core/constants/RESTConstants.java | 4 + .../gui/actions/RebalanceVolumeAction.java | 37 +++++- .../server/resources/VolumesResource.java | 132 ++++++++++++++------- .../server/tasks/RebalanceVolumeTask.java | 103 ++++++++++++++++ .../management/server/utils/GlusterUtil.java | 15 +++ 6 files changed, 255 insertions(+), 45 deletions(-) create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/tasks/RebalanceVolumeTask.java (limited to 'src') 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 c04389d1..338caf89 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 @@ -229,6 +229,15 @@ public class VolumesClient extends AbstractClient { putRequest(volumeName + "/" + RESTConstants.RESOURCE_BRICKS, form); } + + public void rebalanceVolume(String volumeName, boolean fixLayout, boolean migrateData, boolean forcedDataMigrate) { + Form form = new Form(); + form.add(RESTConstants.FORM_PARAM_OPERATION, RESTConstants.TASK_REBALANCE_START); + form.add(RESTConstants.FORM_PARAM_FIX_LAYOUT, fixLayout); + form.add(RESTConstants.FORM_PARAM_MIGRATE_DATA, migrateData); + form.add(RESTConstants.FORM_PARAM_FORCED_DATA_MIGRATE, forcedDataMigrate); + putRequest(volumeName, form); + } public static void main(String[] args) { UsersClient usersClient = new UsersClient(); 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 deabbde7..16f5d7b5 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 @@ -47,6 +47,7 @@ public class RESTConstants { public static final String TASK_STOP = "stop"; public static final String TASK_STATUS = "status"; public static final String TASK_DELETE = "delete"; + public static final String TASK_REBALANCE_START = "rebalanceStart"; public static final String FORM_PARAM_VOLUME_NAME = "name"; public static final String FORM_PARAM_VOLUME_TYPE = "volumeType"; @@ -67,6 +68,9 @@ public class RESTConstants { public static final String FORM_PARAM_SOURCE = "source"; public static final String FORM_PARAM_TARGET = "target"; public static final String FORM_PARAM_AUTO_COMMIT = "autoCommit"; + public static final String FORM_PARAM_FIX_LAYOUT = "fix-layout"; + public static final String FORM_PARAM_MIGRATE_DATA = "migrate-data"; + public static final String FORM_PARAM_FORCED_DATA_MIGRATE = "forced-data-migrate"; public static final String PATH_PARAM_FORMAT = "format"; public static final String PATH_PARAM_VOLUME_NAME = "volumeName"; diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/RebalanceVolumeAction.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/RebalanceVolumeAction.java index 5339beb0..9b55e70a 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/RebalanceVolumeAction.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/RebalanceVolumeAction.java @@ -19,11 +19,44 @@ package com.gluster.storage.management.gui.actions; import org.eclipse.jface.action.IAction; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.widgets.Display; + +import com.gluster.storage.management.client.VolumesClient; +import com.gluster.storage.management.core.model.Volume; public class RebalanceVolumeAction extends AbstractActionDelegate { + private Volume volume; + + @Override + protected void performAction(final IAction action) { + + Display.getDefault().asyncExec(new Runnable() { + + @Override + public void run() { + final String actionDesc = action.getDescription(); + try { + new VolumesClient().rebalanceVolume(volume.getName(), false, false, false); + showInfoDialog(actionDesc, "Volume [" + volume.getName() + "] rebalance started successfully!"); + } catch (Exception e) { + showErrorDialog(actionDesc, + "Volume rebalance cannot started on [" + volume.getName() + "]! Error: [" + e.getMessage() + "]"); + } + + } + }); + } + @Override - protected void performAction(IAction action) { - System.out.println("Running [" + this.getClass().getSimpleName() + "]"); + public void selectionChanged(IAction action, ISelection selection) { + super.selectionChanged(action, selection); + + action.setEnabled(false); + if (selectedEntity instanceof Volume) { + volume = (Volume) selectedEntity; + action.setEnabled(true); + } } @Override 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 c7e18aaa..d85cb006 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 @@ -54,6 +54,9 @@ import static com.gluster.storage.management.core.constants.RESTConstants.RESOUR import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_VOLUMES; import static com.gluster.storage.management.core.constants.RESTConstants.TASK_START; import static com.gluster.storage.management.core.constants.RESTConstants.TASK_STOP; +import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_FIX_LAYOUT; +import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_MIGRATE_DATA; +import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_FORCED_DATA_MIGRATE; import java.io.File; import java.io.IOException; @@ -139,11 +142,11 @@ public class VolumesResource extends AbstractResource { public Response getVolumes(String clusterName, String mediaType) { if (clusterName == null || clusterName.isEmpty()) { - return badRequestResponse("Cluster name must not be empty!"); + return notFoundResponse("Cluster name must not be empty!"); } if (clusterService.getCluster(clusterName) == null) { - return badRequestResponse("Cluster [" + clusterName + "] not found!"); + return notFoundResponse("Cluster [" + clusterName + "] not found!"); } return okResponse(getVolumes(clusterName), mediaType); @@ -176,24 +179,24 @@ public class VolumesResource extends AbstractResource { @FormParam(FORM_PARAM_BRICKS) String bricks, @FormParam(FORM_PARAM_ACCESS_PROTOCOLS) String accessProtocols, @FormParam(FORM_PARAM_VOLUME_OPTIONS) String options) { if(clusterName == null || clusterName.isEmpty()) { - return badRequestResponse("Cluster name must not be empty!"); + return notFoundResponse("Cluster name must not be empty!"); } String missingParam = checkMissingParamsForCreateVolume(volumeName, volumeType, transportType, replicaCount, stripeCount, bricks, accessProtocols, options); if(missingParam != null) { - return badRequestResponse("Parameter [" + missingParam + "] is missing in request!"); + return notFoundResponse("Parameter [" + missingParam + "] is missing in request!"); } if (clusterService.getCluster(clusterName) == null) { - return badRequestResponse("Cluster [" + clusterName + "] not found!"); + return notFoundResponse("Cluster [" + clusterName + "] not found!"); } if (volumeType.equals(VOLUME_TYPE.DISTRIBUTED_MIRROR) && replicaCount <= 0) { - return badRequestResponse("Replica count must be a positive integer"); + return notFoundResponse("Replica count must be a positive integer"); } if (volumeType.equals(VOLUME_TYPE.DISTRIBUTED_STRIPE) && stripeCount <= 0) { - return badRequestResponse("Stripe count must be a positive integer"); + return notFoundResponse("Stripe count must be a positive integer"); } GlusterServer onlineServer = glusterServersResource.getOnlineServer(clusterName); @@ -267,11 +270,11 @@ public class VolumesResource extends AbstractResource { Volume volume = null; if (clusterName == null || clusterName.isEmpty()) { - return badRequestResponse("Cluster name must not be empty!"); + return notFoundResponse("Cluster name must not be empty!"); } if (clusterService.getCluster(clusterName) == null) { - return badRequestResponse("Cluster [" + clusterName + "] not found!"); + return notFoundResponse("Cluster [" + clusterName + "] not found!"); } try { @@ -306,23 +309,30 @@ public class VolumesResource extends AbstractResource { @PUT @Path("{" + PATH_PARAM_VOLUME_NAME + "}") public Response performOperation(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName, - @PathParam(PATH_PARAM_VOLUME_NAME) String volumeName, @FormParam(FORM_PARAM_OPERATION) String operation) { + @PathParam(PATH_PARAM_VOLUME_NAME) String volumeName, @FormParam(FORM_PARAM_OPERATION) String operation, + @FormParam(FORM_PARAM_FIX_LAYOUT) Boolean isFixLayout, + @FormParam(FORM_PARAM_MIGRATE_DATA) Boolean isMigrateData, + @FormParam(FORM_PARAM_FORCED_DATA_MIGRATE) Boolean isForcedDataMigrate) { if (clusterName == null || clusterName.isEmpty()) { - return badRequestResponse("Cluster name must not be empty!"); + return notFoundResponse("Cluster name must not be empty!"); } if (volumeName == null || volumeName.isEmpty()) { - return badRequestResponse("Volume name must not be empty!"); + return notFoundResponse("Volume name must not be empty!"); } if (clusterService.getCluster(clusterName) == null) { - return badRequestResponse("Cluster [" + clusterName + "] not found!"); + return notFoundResponse("Cluster [" + clusterName + "] not found!"); } GlusterServer onlineServer = glusterServersResource.getOnlineServer(clusterName); if (onlineServer == null) { return errorResponse("No online servers found in cluster [" + clusterName + "]"); } + + if (operation.equals(RESTConstants.TASK_REBALANCE_START)) { + return rebalanceVolume(clusterName, volumeName, isFixLayout, isMigrateData, isForcedDataMigrate); + } try { performOperation(volumeName, operation, onlineServer); @@ -359,15 +369,15 @@ public class VolumesResource extends AbstractResource { @PathParam(PATH_PARAM_VOLUME_NAME) String volumeName, @QueryParam(QUERY_PARAM_DELETE_OPTION) Boolean deleteFlag) { if (clusterName == null || clusterName.isEmpty()) { - return badRequestResponse("Cluster name must not be empty"); + return notFoundResponse("Cluster name must not be empty"); } if (volumeName == null || volumeName.isEmpty()) { - return badRequestResponse("Volume name must not be empty"); + return notFoundResponse("Volume name must not be empty"); } if (clusterService.getCluster(clusterName) == null) { - return badRequestResponse("Cluster [" + clusterName + "] not found!"); + return notFoundResponse("Cluster [" + clusterName + "] not found!"); } if (deleteFlag == null) { @@ -408,19 +418,19 @@ public class VolumesResource extends AbstractResource { List brickList = Arrays.asList(bricks.split(",")); // Convert from comma separated string (query // parameter) if (clusterName == null || clusterName.isEmpty()) { - return badRequestResponse("Cluster name must not be empty!"); + return notFoundResponse("Cluster name must not be empty!"); } if (volumeName == null || volumeName.isEmpty()) { - return badRequestResponse("Volume name must not be empty!"); + return notFoundResponse("Volume name must not be empty!"); } if (bricks == null || bricks.isEmpty()) { - return badRequestResponse("Parameter [" + QUERY_PARAM_BRICKS + "] is missing in request!"); + return notFoundResponse("Parameter [" + QUERY_PARAM_BRICKS + "] is missing in request!"); } if (clusterService.getCluster(clusterName) == null) { - return badRequestResponse("Cluster [" + clusterName + "] not found!"); + return notFoundResponse("Cluster [" + clusterName + "] not found!"); } if(deleteFlag == null) { @@ -511,23 +521,23 @@ public class VolumesResource extends AbstractResource { @FormParam(RESTConstants.FORM_PARAM_OPTION_KEY) String key, @FormParam(RESTConstants.FORM_PARAM_OPTION_VALUE) String value) { if (clusterName == null || clusterName.isEmpty()) { - return badRequestResponse("Cluster name must not be empty!"); + return notFoundResponse("Cluster name must not be empty!"); } if(volumeName == null || volumeName.isEmpty()) { - return badRequestResponse("Volume name must not be empty!"); + return notFoundResponse("Volume name must not be empty!"); } if(key == null || key.isEmpty()) { - return badRequestResponse("Parameter [" + FORM_PARAM_OPTION_KEY + "] is missing in request!"); + return notFoundResponse("Parameter [" + FORM_PARAM_OPTION_KEY + "] is missing in request!"); } if(value == null || value.isEmpty()) { - return badRequestResponse("Parameter [" + FORM_PARAM_OPTION_VALUE + "] is missing in request!"); + return notFoundResponse("Parameter [" + FORM_PARAM_OPTION_VALUE + "] is missing in request!"); } if (clusterService.getCluster(clusterName) == null) { - return badRequestResponse("Cluster [" + clusterName + "] not found!"); + return notFoundResponse("Cluster [" + clusterName + "] not found!"); } GlusterServer onlineServer = glusterServersResource.getOnlineServer(clusterName); @@ -561,15 +571,15 @@ public class VolumesResource extends AbstractResource { public Response resetOptions(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName, @PathParam(PATH_PARAM_VOLUME_NAME) String volumeName) { if (clusterName == null || clusterName.isEmpty()) { - return badRequestResponse("Cluster name must not be empty!"); + return notFoundResponse("Cluster name must not be empty!"); } if(volumeName == null || volumeName.isEmpty()) { - return badRequestResponse("Volume name must not be empty!"); + return notFoundResponse("Volume name must not be empty!"); } if (clusterService.getCluster(clusterName) == null) { - return badRequestResponse("Cluster [" + clusterName + "] not found!"); + return notFoundResponse("Cluster [" + clusterName + "] not found!"); } GlusterServer onlineServer = glusterServersResource.getOnlineServer(clusterName); @@ -654,15 +664,15 @@ public class VolumesResource extends AbstractResource { public Response downloadLogs(@PathParam(PATH_PARAM_CLUSTER_NAME) final String clusterName, @PathParam(PATH_PARAM_VOLUME_NAME) final String volumeName) { if (clusterName == null || clusterName.isEmpty()) { - return badRequestResponse("Cluster name must not be empty!"); + return notFoundResponse("Cluster name must not be empty!"); } if (volumeName == null || volumeName.isEmpty()) { - return badRequestResponse("Volume name must not be empty!"); + return notFoundResponse("Volume name must not be empty!"); } if (clusterService.getCluster(clusterName) == null) { - return badRequestResponse("Cluster [" + clusterName + "] not found!"); + return notFoundResponse("Cluster [" + clusterName + "] not found!"); } try { @@ -746,15 +756,15 @@ public class VolumesResource extends AbstractResource { public Response getLogs(String clusterName, String volumeName, String brickName, String severity, String fromTimestamp, String toTimestamp, Integer lineCount, String mediaType) { if (clusterName == null || clusterName.isEmpty()) { - return badRequestResponse("Cluster name must not be empty!"); + return notFoundResponse("Cluster name must not be empty!"); } if (volumeName == null || volumeName.isEmpty()) { - return badRequestResponse("Volume name must not be empty!"); + return notFoundResponse("Volume name must not be empty!"); } if (clusterService.getCluster(clusterName) == null) { - return badRequestResponse("Cluster [" + clusterName + "] not found!"); + return notFoundResponse("Cluster [" + clusterName + "] not found!"); } List logMessages = null; @@ -847,19 +857,19 @@ public class VolumesResource extends AbstractResource { public Response addBricks(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName, @PathParam(PATH_PARAM_VOLUME_NAME) String volumeName, @FormParam(FORM_PARAM_BRICKS) String bricks) { if (clusterName == null || clusterName.isEmpty()) { - return badRequestResponse("Cluster name must not be empty!"); + return notFoundResponse("Cluster name must not be empty!"); } if (volumeName == null || volumeName.isEmpty()) { - return badRequestResponse("Cluster name must not be empty!"); + return notFoundResponse("Cluster name must not be empty!"); } if (bricks == null || bricks.isEmpty()) { - return badRequestResponse("Parameter [" + FORM_PARAM_BRICKS + "] is missing in request!"); + return notFoundResponse("Parameter [" + FORM_PARAM_BRICKS + "] is missing in request!"); } if (clusterService.getCluster(clusterName) == null) { - return badRequestResponse("Cluster [" + clusterName + "] not found!"); + return notFoundResponse("Cluster [" + clusterName + "] not found!"); } GlusterServer onlineServer = glusterServersResource.getOnlineServer(clusterName); @@ -896,23 +906,23 @@ public class VolumesResource extends AbstractResource { @FormParam(FORM_PARAM_TARGET) String toBrick, @FormParam(FORM_PARAM_AUTO_COMMIT) Boolean autoCommit) { if (clusterName == null || clusterName.isEmpty()) { - return badRequestResponse("Cluster name must not be empty!"); + return notFoundResponse("Cluster name must not be empty!"); } if (volumeName == null || volumeName.isEmpty()) { - return badRequestResponse("Volume name must not be empty!"); + return notFoundResponse("Volume name must not be empty!"); } if (fromBrick == null || fromBrick.isEmpty()) { - return badRequestResponse("Parameter [" + FORM_PARAM_SOURCE + "] is missing in request!"); + return notFoundResponse("Parameter [" + FORM_PARAM_SOURCE + "] is missing in request!"); } if (toBrick == null || toBrick.isEmpty()) { - return badRequestResponse("Parameter [" + FORM_PARAM_TARGET + "] is missing in request!"); + return notFoundResponse("Parameter [" + FORM_PARAM_TARGET + "] is missing in request!"); } if (clusterService.getCluster(clusterName) == null) { - return badRequestResponse("Cluster [" + clusterName + "] not found!"); + return notFoundResponse("Cluster [" + clusterName + "] not found!"); } GlusterServer onlineServer = glusterServersResource.getOnlineServer(clusterName); @@ -942,6 +952,42 @@ public class VolumesResource extends AbstractResource { return acceptedResponse(RESTConstants.RESOURCE_PATH_CLUSTERS, clusterName, RESOURCE_TASKS, taskId); } + + private Response rebalanceVolume(String clusterName, String volumeName, Boolean isFixLayout, Boolean isMigrateData, + boolean isForcedDataMigrate) { + + GlusterServer onlineServer = glusterServersResource.getOnlineServer(clusterName); + if (onlineServer == null) { + return errorResponse("No online servers found in cluster [" + clusterName + "]"); + } + + String layout = ""; + String taskId = null; + if (isForcedDataMigrate) { + layout = "forced-data-migrate = true"; + } else if (isMigrateData) { + layout = "migrate-data = true"; + } else if (isFixLayout) { + layout = "fix-layout = true"; + } + + try { + taskId = glusterUtil.rebalanceVolumeStart(volumeName, layout, onlineServer.getName()); + } catch (ConnectionException e) { + // online server has gone offline! try with a different one. + onlineServer = glusterServersResource.getNewOnlineServer(clusterName); + + try { + taskId = glusterUtil.rebalanceVolumeStart(volumeName, layout, onlineServer.getName()); + } catch(Exception e1) { + return errorResponse(e1.getMessage()); + } + } catch(Exception e1) { + return errorResponse(e1.getMessage()); + } + + return acceptedResponse(RESTConstants.RESOURCE_PATH_CLUSTERS, clusterName, RESOURCE_TASKS, taskId); + } 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/tasks/RebalanceVolumeTask.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/tasks/RebalanceVolumeTask.java new file mode 100644 index 00000000..697a40be --- /dev/null +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/tasks/RebalanceVolumeTask.java @@ -0,0 +1,103 @@ +/** + * RebalanceVolumeTask.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.server.tasks; + +import com.gluster.storage.management.core.model.Status; +import com.gluster.storage.management.core.model.Task; +import com.gluster.storage.management.core.model.TaskInfo; +import com.gluster.storage.management.core.model.TaskStatus; +import com.gluster.storage.management.server.utils.SshUtil; + +public class RebalanceVolumeTask extends Task { + + private String layout; + private SshUtil sshUtil = new SshUtil(); + + public RebalanceVolumeTask(TaskInfo taskInfo) { + super(taskInfo); + } + + public RebalanceVolumeTask(String volumeName) { + super(TASK_TYPE.VOLUME_REBALANCE, volumeName); + setTaskDescription(); + getTaskInfo().setCanPause(false); + getTaskInfo().setCanStop(true); + } + + @Override + public String getId() { + return getTaskInfo().getId(); + } + + @Override + public TaskInfo start() { + getTaskInfo().setStatus( + new TaskStatus(new Status(sshUtil.executeRemote(getOnlineServer(), "gluster volume rebalance " + + getTaskInfo().getReference() + " " + getLayout() + " start")))); + return getTaskInfo(); + } + + @Override + public TaskInfo resume() { + getTaskInfo().setStatus( + new TaskStatus(new Status(Status.STATUS_CODE_FAILURE, "Can not suspend volume rebalance"))); + return getTaskInfo(); + } + + @Override + public TaskInfo stop() { + getTaskInfo().setStatus( + new TaskStatus(new Status(sshUtil.executeRemote(getOnlineServer(), "gluster volume rebalance " + + getTaskInfo().getReference() + " stop")))); + return getTaskInfo(); + } + + @Override + public TaskInfo pause() { + getTaskInfo().setStatus( + new TaskStatus(new Status(Status.STATUS_CODE_FAILURE, "Can not pause volume rebalance"))); + return getTaskInfo(); + } + + @Override + public TaskInfo status() { + getTaskInfo().setStatus( + new TaskStatus(new Status(sshUtil.executeRemote(getOnlineServer(), "gluster volume rebalance " + + getTaskInfo().getReference() + " status")))); + return getTaskInfo(); + } + + @Override + public void setTaskDescription() { + TaskInfo taskInfo = getTaskInfo(); + getTaskInfo().setDescription("Volume rebalance running on " + taskInfo.getReference()); + + } + + public void setLayout(String layout) { + this.layout = layout; + } + + public String getLayout() { + return layout; + } + +} 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 670ffb5c..970e1c65 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 @@ -47,6 +47,7 @@ import com.gluster.storage.management.core.utils.ProcessResult; import com.gluster.storage.management.core.utils.StringUtil; import com.gluster.storage.management.server.resources.TasksResource; import com.gluster.storage.management.server.tasks.MigrateDiskTask; +import com.gluster.storage.management.server.tasks.RebalanceVolumeTask; import com.sun.jersey.api.core.InjectParam; @Component @@ -550,6 +551,20 @@ public class GlusterUtil { return taskInfo.getId(); } + + public String rebalanceVolumeStart(String volumeName, String layout, String knownServer) { + + RebalanceVolumeTask rebalanceTask = new RebalanceVolumeTask(volumeName); + rebalanceTask.setOnlineServer(knownServer); + rebalanceTask.setLayout(layout); + + TaskInfo taskInfo = rebalanceTask.start(); + if(taskInfo.isSuccess()) { + taskResource.addTask(rebalanceTask); + } + + return taskInfo.getId(); + } public Status removeBricks(String volumeName, List bricks, String knownServer) { StringBuilder command = new StringBuilder("gluster --mode=script volume remove-brick " + volumeName); -- cgit From eb58d91bb775a897c39ac7303993b361b48f35a9 Mon Sep 17 00:00:00 2001 From: Dhandapani Date: Mon, 27 Jun 2011 16:21:16 +0530 Subject: Story #1: Rebalance Volume --- .../storage/management/client/VolumesClient.java | 14 +++- .../management/core/constants/RESTConstants.java | 2 + .../gui/actions/RebalanceVolumeAction.java | 4 +- .../server/resources/VolumesResource.java | 66 ++++++++++++++-- .../server/tasks/RebalanceVolumeTask.java | 90 ++++++++++++++-------- .../management/server/utils/GlusterUtil.java | 41 ++++++++-- 6 files changed, 169 insertions(+), 48 deletions(-) (limited to 'src') 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 338caf89..4ec3ff13 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 @@ -230,7 +230,7 @@ public class VolumesClient extends AbstractClient { putRequest(volumeName + "/" + RESTConstants.RESOURCE_BRICKS, form); } - public void rebalanceVolume(String volumeName, boolean fixLayout, boolean migrateData, boolean forcedDataMigrate) { + public void rebalanceStart(String volumeName, Boolean fixLayout, Boolean migrateData, Boolean forcedDataMigrate) { Form form = new Form(); form.add(RESTConstants.FORM_PARAM_OPERATION, RESTConstants.TASK_REBALANCE_START); form.add(RESTConstants.FORM_PARAM_FIX_LAYOUT, fixLayout); @@ -238,6 +238,18 @@ public class VolumesClient extends AbstractClient { form.add(RESTConstants.FORM_PARAM_FORCED_DATA_MIGRATE, forcedDataMigrate); putRequest(volumeName, form); } + + public void rebalanceStatus(String volumeName) { + Form form = new Form(); + form.add(RESTConstants.FORM_PARAM_OPERATION, RESTConstants.TASK_REBALANCE_STATUS); + putRequest(volumeName, form); + } + + public void rebalanceStop(String volumeName) { + Form form = new Form(); + form.add(RESTConstants.FORM_PARAM_OPERATION, RESTConstants.TASK_REBALANCE_STOP); + putRequest(volumeName, form); + } public static void main(String[] args) { UsersClient usersClient = new UsersClient(); 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 abc2d852..527ae2a1 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 @@ -49,6 +49,8 @@ public class RESTConstants { public static final String TASK_STATUS = "status"; public static final String TASK_DELETE = "delete"; public static final String TASK_REBALANCE_START = "rebalanceStart"; + public static final String TASK_REBALANCE_STATUS = "rebalanceStatus"; + public static final String TASK_REBALANCE_STOP = "rebalanceStop"; public static final String FORM_PARAM_VOLUME_NAME = "name"; public static final String FORM_PARAM_VOLUME_TYPE = "volumeType"; diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/RebalanceVolumeAction.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/RebalanceVolumeAction.java index 9b55e70a..33ca0e5b 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/RebalanceVolumeAction.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/RebalanceVolumeAction.java @@ -37,11 +37,11 @@ public class RebalanceVolumeAction extends AbstractActionDelegate { public void run() { final String actionDesc = action.getDescription(); try { - new VolumesClient().rebalanceVolume(volume.getName(), false, false, false); + new VolumesClient().rebalanceStart(volume.getName(), false, false, false); showInfoDialog(actionDesc, "Volume [" + volume.getName() + "] rebalance started successfully!"); } catch (Exception e) { showErrorDialog(actionDesc, - "Volume rebalance cannot started on [" + volume.getName() + "]! Error: [" + e.getMessage() + "]"); + "Volume rebalance could not be started on [" + volume.getName() + "]! Error: [" + e.getMessage() + "]"); } } 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 73d3ccc8..0bb61245 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 @@ -331,7 +331,11 @@ public class VolumesResource extends AbstractResource { } if (operation.equals(RESTConstants.TASK_REBALANCE_START)) { - return rebalanceVolume(clusterName, volumeName, isFixLayout, isMigrateData, isForcedDataMigrate); + return rebalanceStart(clusterName, volumeName, isFixLayout, isMigrateData, isForcedDataMigrate); + } else if (operation.equals(RESTConstants.TASK_REBALANCE_STATUS)) { + return rebalanceStatus(clusterName, volumeName); + } else if (operation.equals(RESTConstants.TASK_REBALANCE_STOP)) { + return rebalanceStop(clusterName, volumeName); } try { @@ -946,12 +950,12 @@ public class VolumesResource extends AbstractResource { return acceptedResponse(RESTConstants.RESOURCE_PATH_CLUSTERS, clusterName, RESOURCE_TASKS, taskId); } - private Response rebalanceVolume(String clusterName, String volumeName, Boolean isFixLayout, Boolean isMigrateData, - boolean isForcedDataMigrate) { + private Response rebalanceStart(String clusterName, String volumeName, Boolean isFixLayout, Boolean isMigrateData, + Boolean isForcedDataMigrate) { GlusterServer onlineServer = glusterServersResource.getOnlineServer(clusterName); if (onlineServer == null) { - return errorResponse("No online servers found in cluster [" + clusterName + "]"); + return notFoundResponse("No online servers found in cluster [" + clusterName + "]"); } String layout = ""; @@ -965,13 +969,13 @@ public class VolumesResource extends AbstractResource { } try { - taskId = glusterUtil.rebalanceVolumeStart(volumeName, layout, onlineServer.getName()); + taskId = glusterUtil.rebalanceStart(volumeName, layout, onlineServer.getName()); } catch (ConnectionException e) { // online server has gone offline! try with a different one. onlineServer = glusterServersResource.getNewOnlineServer(clusterName); try { - taskId = glusterUtil.rebalanceVolumeStart(volumeName, layout, onlineServer.getName()); + taskId = glusterUtil.rebalanceStart(volumeName, layout, onlineServer.getName()); } catch(Exception e1) { return errorResponse(e1.getMessage()); } @@ -981,6 +985,56 @@ public class VolumesResource extends AbstractResource { return acceptedResponse(RESTConstants.RESOURCE_PATH_CLUSTERS, clusterName, RESOURCE_TASKS, taskId); } + + private Response rebalanceStatus(String clusterName, String volumeName) { + GlusterServer onlineServer = glusterServersResource.getOnlineServer(clusterName); + if (onlineServer == null) { + return notFoundResponse("No online servers found in cluster [" + clusterName + "]"); + } + + String taskId = null; + try { + taskId = glusterUtil.rebalanceStatus(volumeName, onlineServer.getName()); + } catch (ConnectionException e) { + // online server has gone offline! try with a different one. + onlineServer = glusterServersResource.getNewOnlineServer(clusterName); + + try { + taskId = glusterUtil.rebalanceStatus(volumeName, onlineServer.getName()); + } catch (Exception e1) { + return errorResponse(e1.getMessage()); + } + } catch(Exception e1) { + return errorResponse(e1.getMessage()); + } + + return acceptedResponse(RESTConstants.RESOURCE_PATH_CLUSTERS, clusterName, RESOURCE_TASKS, taskId); + } + + private Response rebalanceStop(String clusterName, String volumeName) { + GlusterServer onlineServer = glusterServersResource.getOnlineServer(clusterName); + if (onlineServer == null) { + return notFoundResponse("No online servers found in cluster [" + clusterName + "]"); + } + + String taskId = null; + try { + taskId = glusterUtil.rebalanceStop(volumeName, onlineServer.getName()); + } catch (ConnectionException e) { + // online server has gone offline! try with a different one. + onlineServer = glusterServersResource.getNewOnlineServer(clusterName); + + try { + taskId = glusterUtil.rebalanceStop(volumeName, onlineServer.getName()); + } catch (Exception e1) { + return errorResponse(e1.getMessage()); + } + } catch(Exception e1) { + return errorResponse(e1.getMessage()); + } + + return acceptedResponse(RESTConstants.RESOURCE_PATH_CLUSTERS, clusterName, RESOURCE_TASKS, taskId); + } 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/tasks/RebalanceVolumeTask.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/tasks/RebalanceVolumeTask.java index 697a40be..720c050e 100644 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/tasks/RebalanceVolumeTask.java +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/tasks/RebalanceVolumeTask.java @@ -23,7 +23,9 @@ package com.gluster.storage.management.server.tasks; import com.gluster.storage.management.core.model.Status; import com.gluster.storage.management.core.model.Task; import com.gluster.storage.management.core.model.TaskInfo; +import com.gluster.storage.management.core.model.TaskInfo.TASK_TYPE; import com.gluster.storage.management.core.model.TaskStatus; +import com.gluster.storage.management.core.utils.ProcessResult; import com.gluster.storage.management.server.utils.SshUtil; public class RebalanceVolumeTask extends Task { @@ -36,60 +38,78 @@ public class RebalanceVolumeTask extends Task { } public RebalanceVolumeTask(String volumeName) { - super(TASK_TYPE.VOLUME_REBALANCE, volumeName); - setTaskDescription(); - getTaskInfo().setCanPause(false); - getTaskInfo().setCanStop(true); + super(TASK_TYPE.VOLUME_REBALANCE, volumeName, "Volume rebalance running on " + volumeName, false, true, false); } @Override public String getId() { - return getTaskInfo().getId(); + return taskInfo.getType() + "-" + taskInfo.getReference(); } @Override - public TaskInfo start() { - getTaskInfo().setStatus( - new TaskStatus(new Status(sshUtil.executeRemote(getOnlineServer(), "gluster volume rebalance " - + getTaskInfo().getReference() + " " + getLayout() + " start")))); - return getTaskInfo(); + public void start() { + String command = "gluster volume rebalance " + getTaskInfo().getReference() + " " + getLayout() + " start"; + ProcessResult processResult = sshUtil.executeRemote(serverName, command); + TaskStatus taskStatus = new TaskStatus(); + if (processResult.isSuccess()) { + if (processResult.getOutput().trim().matches("*has been successful$")) { + taskStatus.setCode(Status.STATUS_CODE_RUNNING); + } else { + taskStatus.setCode(Status.STATUS_CODE_FAILURE); + } + } else { + taskStatus.setCode(Status.STATUS_CODE_FAILURE); + } + taskStatus.setMessage(processResult.getOutput()); // Common + getTaskInfo().setStatus(taskStatus); } @Override - public TaskInfo resume() { + public void resume() { getTaskInfo().setStatus( - new TaskStatus(new Status(Status.STATUS_CODE_FAILURE, "Can not suspend volume rebalance"))); - return getTaskInfo(); + new TaskStatus(new Status(Status.STATUS_CODE_FAILURE, "Pause/Resume is not supported in Volume Rebalance"))); } @Override - public TaskInfo stop() { - getTaskInfo().setStatus( - new TaskStatus(new Status(sshUtil.executeRemote(getOnlineServer(), "gluster volume rebalance " - + getTaskInfo().getReference() + " stop")))); - return getTaskInfo(); + public void stop() { + String command = "gluster volume rebalance " + getTaskInfo().getReference() + " stop"; + ProcessResult processResult = sshUtil.executeRemote(serverName, command); + TaskStatus taskStatus = new TaskStatus(); + if (processResult.isSuccess()) { + if (processResult.getOutput().trim().matches("*has been successful$")) { + taskStatus.setCode(Status.STATUS_CODE_SUCCESS); + } else { + taskStatus.setCode(Status.STATUS_CODE_FAILURE); + } + } else { + taskStatus.setCode(Status.STATUS_CODE_FAILURE); + } + taskStatus.setMessage(processResult.getOutput()); // Common + getTaskInfo().setStatus(taskStatus); } @Override - public TaskInfo pause() { + public void pause() { getTaskInfo().setStatus( - new TaskStatus(new Status(Status.STATUS_CODE_FAILURE, "Can not pause volume rebalance"))); - return getTaskInfo(); + new TaskStatus(new Status(Status.STATUS_CODE_FAILURE, "Pause/Resume is not supported in Volume Rebalance"))); } @Override - public TaskInfo status() { - getTaskInfo().setStatus( - new TaskStatus(new Status(sshUtil.executeRemote(getOnlineServer(), "gluster volume rebalance " - + getTaskInfo().getReference() + " status")))); - return getTaskInfo(); - } - - @Override - public void setTaskDescription() { - TaskInfo taskInfo = getTaskInfo(); - getTaskInfo().setDescription("Volume rebalance running on " + taskInfo.getReference()); - + public TaskStatus checkStatus() { + String command = "gluster volume rebalance " + getTaskInfo().getReference() + " status"; + ProcessResult processResult = sshUtil.executeRemote(serverName, command); + TaskStatus taskStatus = new TaskStatus(); + if (processResult.isSuccess()) { + if (processResult.getOutput().matches("Rebalance completed!")) { + taskStatus.setCode(Status.STATUS_CODE_SUCCESS); + } else { + taskStatus.setCode(Status.STATUS_CODE_RUNNING); + } + } else { + taskStatus.setCode(Status.STATUS_CODE_FAILURE); + } + taskStatus.setMessage(processResult.getOutput()); // Common + return taskStatus; } public void setLayout(String layout) { @@ -100,4 +120,8 @@ public class RebalanceVolumeTask extends Task { return layout; } + @Override + public void commit() { + // TODO Auto-generated method stub + } } 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 f75810df..767b15c3 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 @@ -36,7 +36,7 @@ import com.gluster.storage.management.core.model.Brick.BRICK_STATUS; 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.TaskInfo.TASK_TYPE; +import com.gluster.storage.management.core.model.TaskInfo; 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; @@ -554,18 +554,47 @@ public class GlusterUtil { return migrateDiskTask.getId(); } - public String rebalanceVolumeStart(String volumeName, String layout, String knownServer) { + public String rebalanceStart(String volumeName, String layout, String knownServer) { RebalanceVolumeTask rebalanceTask = new RebalanceVolumeTask(volumeName); rebalanceTask.setOnlineServer(knownServer); rebalanceTask.setLayout(layout); + rebalanceTask.start(); + int status = rebalanceTask.getTaskInfo().getStatus().getCode(); - TaskInfo taskInfo = rebalanceTask.start(); - if(taskInfo.isSuccess()) { + if(status != Status.STATUS_CODE_FAILURE) { + TasksResource taskResource = new TasksResource(); taskResource.addTask(rebalanceTask); + } else { + throw new GlusterRuntimeException( rebalanceTask.getTaskInfo().getStatus().getMessage()); } - - return taskInfo.getId(); + return rebalanceTask.getId(); + } + + public String rebalanceStatus(String volumeName, String knownServer) { + RebalanceVolumeTask rebalanceTask = new RebalanceVolumeTask(volumeName); + rebalanceTask.setOnlineServer(knownServer); + + rebalanceTask.checkStatus(); + int status = rebalanceTask.getTaskInfo().getStatus().getCode(); + + if (status == Status.STATUS_CODE_FAILURE) { + throw new GlusterRuntimeException(rebalanceTask.getTaskInfo().getStatus().getMessage()); + } + return rebalanceTask.getId(); + } + + public String rebalanceStop(String volumeName, String knownServer) { + RebalanceVolumeTask rebalanceTask = new RebalanceVolumeTask(volumeName); + rebalanceTask.setOnlineServer(knownServer); + + rebalanceTask.stop(); + int status = rebalanceTask.getTaskInfo().getStatus().getCode(); + + if (status == Status.STATUS_CODE_FAILURE) { + throw new GlusterRuntimeException(rebalanceTask.getTaskInfo().getStatus().getMessage()); + } + return rebalanceTask.getId(); } public Status removeBricks(String volumeName, List bricks, String knownServer) { -- cgit