summaryrefslogtreecommitdiffstats
path: root/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks
diff options
context:
space:
mode:
authorShireesh Anjal <shireesh@gluster.com>2011-11-25 20:13:35 +0530
committerShireesh Anjal <shireesh@gluster.com>2011-11-25 20:13:35 +0530
commit1142b0e41de39010de7845cf70d71dbb001fc1dc (patch)
tree3513487f65c1a7df47996bd2852393aceaac1b8a /src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks
parent92c52d8edf285945d31e446503fc742fde9dcc49 (diff)
Renamed projects / packages com.gluster.* to org.gluster.*
Diffstat (limited to 'src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks')
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/InitServerTask.java161
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/InitializeDiskTask.java198
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/MigrateBrickTask.java220
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/RebalanceVolumeTask.java141
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/ServerSyncTask.java168
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/Task.java113
6 files changed, 1001 insertions, 0 deletions
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/InitServerTask.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/InitServerTask.java
new file mode 100644
index 00000000..3193d926
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/InitServerTask.java
@@ -0,0 +1,161 @@
+/**
+ * GlusterServerInitializer.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 org.gluster.storage.management.gateway.tasks;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import javax.servlet.ServletContext;
+
+import org.apache.derby.tools.ij;
+import org.gluster.storage.management.core.constants.CoreConstants;
+import org.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import org.gluster.storage.management.gateway.data.ClusterInfo;
+import org.gluster.storage.management.gateway.data.PersistenceDao;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.RowCallbackHandler;
+import org.springframework.jdbc.core.support.JdbcDaoSupport;
+import org.springframework.security.authentication.dao.SaltSource;
+import org.springframework.security.authentication.encoding.PasswordEncoder;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+
+
+/**
+ * Initializes the Gluster Management Server.
+ */
+public class InitServerTask extends JdbcDaoSupport {
+ @Autowired
+ private PasswordEncoder passwordEncoder;
+
+ @Autowired
+ private SaltSource saltSource;
+
+ @Autowired
+ private UserDetailsService userDetailsService;
+
+ @Autowired
+ private String appVersion;
+
+ @Autowired
+ private PersistenceDao<ClusterInfo> clusterDao;
+
+ @Autowired
+ ServletContext servletContext;
+
+ private static final String SCRIPT_DIR = "data/scripts/";
+
+ public void securePasswords() {
+ getJdbcTemplate().query("select username, password from users", new RowCallbackHandler() {
+ @Override
+ public void processRow(ResultSet rs) throws SQLException {
+ String username = rs.getString(1);
+ String password = rs.getString(2);
+ UserDetails user = userDetailsService.loadUserByUsername(username);
+
+ String encodedPassword = passwordEncoder.encodePassword(password, saltSource.getSalt(user));
+ getJdbcTemplate().update("update users set password = ? where username = ?", encodedPassword, username);
+ logger.debug("Updating password for username: " + username);
+ }
+ });
+ }
+
+ private void executeScript(File script) {
+ ByteArrayOutputStream sqlOut = new ByteArrayOutputStream();
+ int numOfExceptions;
+ try {
+ numOfExceptions = ij.runScript(getJdbcTemplate().getDataSource().getConnection(), new FileInputStream(
+ script), CoreConstants.ENCODING_UTF8, sqlOut, CoreConstants.ENCODING_UTF8);
+ String output = sqlOut.toString();
+ sqlOut.close();
+ logger.debug("Data script [" + script.getName() + "] returned with exit status [" + numOfExceptions
+ + "] and output [" + output + "]");
+ if (numOfExceptions != 0) {
+ throw new GlusterRuntimeException("Server data initialization script [ " + script.getName()
+ + "] failed with [" + numOfExceptions + "] exceptions! [" + output + "]");
+ }
+ } catch (Exception ex) {
+ throw new GlusterRuntimeException("Server data initialization script [" + script.getName() + "] failed!",
+ ex);
+ }
+ }
+
+ private void initDatabase() {
+ logger.info("Initializing server data...");
+ executeScriptsFrom(getDirFromRelativePath(SCRIPT_DIR + appVersion));
+
+ securePasswords(); // encrypt the passwords
+ }
+
+ private File getDirFromRelativePath(String relativePath) {
+ String scriptDirPath = servletContext.getRealPath(relativePath);
+ File scriptDir = new File(scriptDirPath);
+ return scriptDir;
+ }
+
+ private void executeScriptsFrom(File scriptDir) {
+ if (!scriptDir.exists()) {
+ throw new GlusterRuntimeException("Script directory [" + scriptDir.getAbsolutePath() + "] doesn't exist!");
+ }
+
+ List<File> scripts = Arrays.asList(scriptDir.listFiles());
+ if(scripts.size() == 0) {
+ throw new GlusterRuntimeException("Script directory [" + scriptDir.getAbsolutePath() + "] is empty!");
+ }
+
+ Collections.sort(scripts);
+ for (File script : scripts) {
+ executeScript(script);
+ }
+ }
+
+ /**
+ * Initializes the server database, if running for the first time.
+ */
+ public synchronized void initServer() {
+ try {
+ String dbVersion = getDBVersion();
+ if (!appVersion.equals(dbVersion)) {
+ logger.info("App version [" + appVersion + "] differs from data version [" + dbVersion
+ + "]. Trying to upgrade data...");
+ upgradeData(dbVersion, appVersion);
+ }
+ } catch (Exception ex) {
+ logger.info("No cluster created yet. DB version query failed with error [" + ex.getMessage() + "]", ex);
+ // Database not created yet. Create it!
+ initDatabase();
+ }
+ }
+
+ private void upgradeData(String fromVersion, String toVersion) {
+ executeScriptsFrom(getDirFromRelativePath(SCRIPT_DIR + fromVersion + "-" + toVersion));
+ }
+
+ private String getDBVersion() {
+ return (String) clusterDao.getSingleResultFromSQL("select version from version");
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/InitializeDiskTask.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/InitializeDiskTask.java
new file mode 100644
index 00000000..45be980a
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/InitializeDiskTask.java
@@ -0,0 +1,198 @@
+/**
+ * InitializeDiskTask.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 org.gluster.storage.management.gateway.tasks;
+
+import org.gluster.storage.management.core.constants.GlusterConstants;
+import org.gluster.storage.management.core.exceptions.ConnectionException;
+import org.gluster.storage.management.core.model.InitDiskStatusResponse;
+import org.gluster.storage.management.core.model.Status;
+import org.gluster.storage.management.core.model.TaskInfo;
+import org.gluster.storage.management.core.model.TaskStatus;
+import org.gluster.storage.management.core.model.InitDiskStatusResponse.FORMAT_STATUS;
+import org.gluster.storage.management.core.model.TaskInfo.TASK_TYPE;
+import org.gluster.storage.management.gateway.services.ClusterService;
+import org.gluster.storage.management.gateway.utils.ServerUtil;
+import org.springframework.context.ApplicationContext;
+import org.springframework.web.context.ContextLoader;
+
+import com.sun.jersey.core.util.Base64;
+
+public class InitializeDiskTask extends Task {
+
+ private static final String INITIALIZE_DISK_SCRIPT = "format_device.py";
+ private static final String INITIALIZE_DISK_STATUS_SCRIPT = "get_format_device_status.py";
+
+ private String serverName;
+ private String diskName;
+ private String fsType;
+ private String mountPoint;
+ private ServerUtil serverUtil;
+
+ public InitializeDiskTask(ClusterService clusterService, String clusterName, String serverName, String diskName,
+ String fsType, String mountPoint) {
+ // Reference contains "Server:disk"
+ super(clusterService, clusterName, TASK_TYPE.DISK_FORMAT, serverName + ":" + diskName, "Initialize disk "
+ + serverName + ":" + diskName, false, false, false);
+
+ setServerName(serverName);
+ setDiskName(diskName);
+ setFsType(fsType);
+ setMountpoint(mountPoint);
+ taskInfo.setName(getId());
+ init();
+ }
+
+ public InitializeDiskTask(ClusterService clusterService, String clusterName, TaskInfo info) {
+ super(clusterService, clusterName, info);
+ init();
+ }
+
+ private void init() {
+ ApplicationContext ctx = ContextLoader.getCurrentWebApplicationContext();
+ serverUtil = ctx.getBean(ServerUtil.class);
+ }
+
+ @Override
+ public String getId() {
+ return new String(
+ Base64.encode(getClusterName() + "-" + taskInfo.getType() + "-" + serverName + ":" + diskName));
+ }
+
+ @Override
+ public void resume() {
+ getTaskInfo().setStatus(
+ new TaskStatus(new Status(Status.STATUS_CODE_FAILURE,
+ "Stop/Pause/Resume is not supported in Disk Initialization")));
+ }
+
+ @Override
+ public void stop() {
+ getTaskInfo().setStatus(
+ new TaskStatus(new Status(Status.STATUS_CODE_FAILURE,
+ "Stop/Pause/Resume is not supported in Disk Initialization")));
+ }
+
+ @Override
+ public void pause() {
+ getTaskInfo().setStatus(
+ new TaskStatus(new Status(Status.STATUS_CODE_FAILURE,
+ "Stop/Pause/Resume is not supported in Disk Initialization")));
+ }
+
+ @Override
+ public void commit() {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public TASK_TYPE getType() {
+ return TASK_TYPE.DISK_FORMAT;
+ }
+
+
+ @Override
+ public void start() {
+ try {
+ startInitializeDisk(serverName);
+ } catch(ConnectionException e) {
+ // online server might have gone offline. update the failure status
+ getTaskInfo().setStatus(new TaskStatus(new Status(Status.STATUS_CODE_FAILURE, e.getMessage())));
+ }
+ }
+
+ private void startInitializeDisk(String serverName) {
+ String output = serverUtil.executeScriptOnServer(serverName, INITIALIZE_DISK_SCRIPT + " " + getFsType() + " \""
+ + getMountpoint() + "\" " + getDiskName() );
+ TaskStatus taskStatus = new TaskStatus(new Status(Status.STATUS_CODE_RUNNING, output));
+ taskStatus.setPercentageSupported((getFsType().equals(GlusterConstants.FSTYPE_XFS)) ? false : true);
+ getTaskInfo().setStatus(taskStatus);
+ }
+
+ @Override
+ public TaskStatus checkStatus() {
+
+ try {
+ return getInitializingDeviceStatus(serverName, getDiskName());
+ } catch(ConnectionException e) {
+ // online server might have gone offline. update the failure status
+ return new TaskStatus(new Status(Status.STATUS_CODE_FAILURE, e.getMessage()));
+ }
+ }
+
+ private TaskStatus getInitializingDeviceStatus(String serverName, String diskName) {
+ InitDiskStatusResponse initDiskStatusResponse;
+ TaskStatus taskStatus = new TaskStatus();
+
+ try {
+ initDiskStatusResponse = serverUtil.executeScriptOnServer(serverName, INITIALIZE_DISK_STATUS_SCRIPT + " "
+ + diskName, InitDiskStatusResponse.class);
+ } catch(RuntimeException e) {
+ taskStatus.setCode(Status.STATUS_CODE_FAILURE);
+ taskStatus.setMessage(e.getMessage());
+ throw e;
+ }
+
+ if (initDiskStatusResponse.getFormatStatus() == FORMAT_STATUS.COMPLETED) {
+ taskStatus.setCode(Status.STATUS_CODE_SUCCESS);
+ } else if (initDiskStatusResponse.getFormatStatus() == FORMAT_STATUS.IN_PROGRESS) {
+ taskStatus.setCode(Status.STATUS_CODE_RUNNING);
+ taskStatus.setPercentCompleted(Math.round(initDiskStatusResponse.getCompletedBlocks()
+ / initDiskStatusResponse.getTotalBlocks() * 100));
+ } else if(initDiskStatusResponse.getFormatStatus() == FORMAT_STATUS.NOT_RUNNING) {
+ taskStatus.setCode(Status.STATUS_CODE_FAILURE);
+ }
+
+ taskStatus.setMessage(initDiskStatusResponse.getMessage());
+ return taskStatus;
+ }
+
+ public void setDiskName(String diskName) {
+ this.diskName = diskName;
+ }
+
+ public String getDiskName() {
+ return diskName;
+ }
+
+ public void setServerName(String serverName) {
+ this.serverName = serverName;
+ }
+
+ public String getServerName() {
+ return serverName;
+ }
+
+ public void setFsType(String fsType) {
+ this.fsType = fsType;
+ }
+
+ public String getFsType() {
+ return fsType;
+ }
+
+ public void setMountpoint(String deviceMountPoint) {
+ this.mountPoint = deviceMountPoint;
+ }
+
+ public String getMountpoint() {
+ return mountPoint;
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/MigrateBrickTask.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/MigrateBrickTask.java
new file mode 100644
index 00000000..8a31f9a9
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/MigrateBrickTask.java
@@ -0,0 +1,220 @@
+/**
+ * MigrateDiskTask.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 org.gluster.storage.management.gateway.tasks;
+
+import org.gluster.storage.management.core.exceptions.ConnectionException;
+import org.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import org.gluster.storage.management.core.model.Status;
+import org.gluster.storage.management.core.model.TaskStatus;
+import org.gluster.storage.management.core.model.TaskInfo.TASK_TYPE;
+import org.gluster.storage.management.gateway.services.ClusterService;
+import org.gluster.storage.management.gateway.services.GlusterInterfaceService;
+import org.gluster.storage.management.gateway.utils.ServerUtil;
+import org.springframework.context.ApplicationContext;
+import org.springframework.web.context.ContextLoader;
+
+import com.sun.jersey.core.util.Base64;
+
+public class MigrateBrickTask extends Task {
+
+ private String fromBrick;
+ private String toBrick;
+ private Boolean autoCommit;
+ private GlusterInterfaceService glusterInterface;
+ protected ServerUtil serverUtil;
+
+ public String getFromBrick() {
+ return fromBrick;
+ }
+
+ public void setFromBrick(String fromBrick) {
+ this.fromBrick = fromBrick;
+ }
+
+ public String getToBrick() {
+ return toBrick;
+ }
+
+ public void setToBrick(String toBrick) {
+ this.toBrick = toBrick;
+ }
+
+ public Boolean getAutoCommit() {
+ return autoCommit;
+ }
+
+ public void setAutoCommit(Boolean autoCommit) {
+ this.autoCommit = autoCommit;
+ }
+
+ public MigrateBrickTask(ClusterService clusterService, String clusterName, String volumeName, String fromBrick,
+ String toBrick) {
+ super(clusterService, clusterName, TASK_TYPE.BRICK_MIGRATE, volumeName + "#" + fromBrick + "#" + toBrick,
+ "Brick Migration on volume [" + volumeName + "] from [" + fromBrick + "] to [" + toBrick + "]", true,
+ true, true);
+ setFromBrick(fromBrick);
+ setToBrick(toBrick);
+ taskInfo.setName(getId());
+ init();
+ }
+
+ private void init() {
+ ApplicationContext ctx = ContextLoader.getCurrentWebApplicationContext();
+ glusterInterface = ctx.getBean(GlusterInterfaceService.class);
+ serverUtil = ctx.getBean(ServerUtil.class);
+ }
+
+ @Override
+ public String getId() {
+ return new String(Base64.encode(clusterName + "-" + taskInfo.getType() + "-" + taskInfo.getReference() + "-" + fromBrick + "-"
+ + toBrick));
+ }
+
+ @Override
+ public void start() {
+ try {
+ startMigration(getOnlineServer().getName());
+ } catch (Exception e) {
+ // check if online server has gone offline. If yes, try again one more time.
+ if (e instanceof ConnectionException || serverUtil.isServerOnline(getOnlineServer()) == false) {
+ // online server might have gone Offline. try with a new one.
+ startMigration(getNewOnlineServer().getName());
+ } else {
+ throw new GlusterRuntimeException(e.getMessage());
+ }
+ }
+ }
+
+ private void startMigration(String onlineServerName) {
+ String volumeName = getTaskInfo().getReference().split("#")[0];
+ glusterInterface.startBrickMigration(onlineServerName, volumeName, getFromBrick(), getToBrick());
+ getTaskInfo().setStatus(new TaskStatus(new Status(Status.STATUS_CODE_RUNNING, "Brick Migration Started.")));
+ }
+
+ @Override
+ public void pause() {
+ try {
+ pauseMigration(getOnlineServer().getName());
+ } catch (Exception e) {
+ // check if online server has gone offline. If yes, try again one more time.
+ if (e instanceof ConnectionException || serverUtil.isServerOnline(getOnlineServer()) == false) {
+ // online server might have gone offline. try with a new one.
+ pauseMigration(getNewOnlineServer().getName());
+ } else {
+ throw new GlusterRuntimeException(e.getMessage());
+ }
+ }
+ }
+
+ private void pauseMigration(String onlineServer) {
+ String volumeName = getTaskInfo().getReference().split("#")[0];
+ glusterInterface.pauseBrickMigration(onlineServer, volumeName, getFromBrick(), getToBrick());
+ TaskStatus taskStatus = new TaskStatus();
+ taskStatus.setCode(Status.STATUS_CODE_PAUSE);
+ taskStatus.setMessage("Brick Migration Paused");
+ getTaskInfo().setStatus(taskStatus);
+ }
+
+ @Override
+ public void resume() {
+ start();
+ }
+
+ @Override
+ public void commit() {
+ try {
+ commitMigration(getOnlineServer().getName());
+ } catch (Exception e) {
+ // check if online server has gone offline. If yes, try again one more time.
+ if (e instanceof ConnectionException || serverUtil.isServerOnline(getOnlineServer()) == false) {
+ // online server might have gone offline. try with a new one.
+ commitMigration(getNewOnlineServer().getName());
+ } else {
+ throw new GlusterRuntimeException(e.getMessage());
+ }
+ }
+ }
+
+ private void commitMigration(String serverName) {
+ String volumeName = getTaskInfo().getReference().split("#")[0];
+ glusterInterface.commitBrickMigration(serverName, volumeName, getFromBrick(), getToBrick());
+ TaskStatus taskStatus = new TaskStatus();
+ taskStatus.setCode(Status.STATUS_CODE_SUCCESS);
+ taskStatus.setMessage("Brick Migration Committed.");
+ getTaskInfo().setStatus(taskStatus);
+ }
+
+ @Override
+ public void stop() {
+ try {
+ stopMigration(getOnlineServer().getName());
+ } catch (Exception e) {
+ // check if online server has gone offline. If yes, try again one more time.
+ if (e instanceof ConnectionException || serverUtil.isServerOnline(getOnlineServer()) == false) {
+ // online server might have gone offline. try with a new one.
+ stopMigration(getNewOnlineServer().getName());
+ } else {
+ throw new GlusterRuntimeException(e.getMessage());
+ }
+ }
+ }
+
+ private void stopMigration(String serverName) {
+ String volumeName = getTaskInfo().getReference().split("#")[0];
+ glusterInterface.stopBrickMigration(serverName, volumeName, getFromBrick(), getToBrick());
+ TaskStatus taskStatus = new TaskStatus();
+ taskStatus.setCode(Status.STATUS_CODE_SUCCESS);
+ taskStatus.setMessage("Brick Migration Stopped");
+ getTaskInfo().setStatus(taskStatus);
+ }
+
+ @Override
+ public TaskStatus checkStatus() {
+ try {
+ return checkMigrationStatus(getOnlineServer().getName());
+ } catch (Exception e) {
+ // check if online server has gone offline. If yes, try again one more time.
+ if (e instanceof ConnectionException || serverUtil.isServerOnline(getOnlineServer()) == false) {
+ // online server might have gone offline. try with a new one.
+ return checkMigrationStatus(getNewOnlineServer().getName());
+ }
+ }
+ return null;
+ }
+
+ private TaskStatus checkMigrationStatus(String serverName) {
+ // For committed task, status command (CLI) is invalid, just return current status
+ if (taskInfo.getStatus().getCode() == Status.STATUS_CODE_SUCCESS) {
+ return taskInfo.getStatus();
+ }
+
+ String volumeName = getTaskInfo().getReference().split("#")[0];
+ TaskStatus taskStatus = glusterInterface.checkBrickMigrationStatus(serverName, volumeName, getFromBrick(),
+ getToBrick());
+ if (autoCommit && taskStatus.isCommitPending()) {
+ commitMigration(serverName);
+ return taskInfo.getStatus(); // return the committed status
+ }
+
+ taskInfo.setStatus(taskStatus); // Update the task status
+ return taskStatus;
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/RebalanceVolumeTask.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/RebalanceVolumeTask.java
new file mode 100644
index 00000000..288179e9
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/RebalanceVolumeTask.java
@@ -0,0 +1,141 @@
+/**
+ * RebalanceVolumeTask.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 org.gluster.storage.management.gateway.tasks;
+
+import org.gluster.storage.management.core.exceptions.ConnectionException;
+import org.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import org.gluster.storage.management.core.model.Status;
+import org.gluster.storage.management.core.model.TaskStatus;
+import org.gluster.storage.management.core.model.TaskInfo.TASK_TYPE;
+import org.gluster.storage.management.gateway.services.ClusterService;
+import org.gluster.storage.management.gateway.services.GlusterInterfaceService;
+import org.gluster.storage.management.gateway.utils.ServerUtil;
+import org.springframework.context.ApplicationContext;
+import org.springframework.web.context.ContextLoader;
+
+import com.sun.jersey.core.util.Base64;
+
+public class RebalanceVolumeTask extends Task {
+
+ private String layout;
+ private String serverName;
+ private ServerUtil serverUtil;
+ private GlusterInterfaceService glusterUtil;
+
+ public RebalanceVolumeTask(ClusterService clusterService, String clusterName, String volumeName, String layout) {
+ super(clusterService, clusterName, TASK_TYPE.VOLUME_REBALANCE, volumeName, "Volume " + volumeName
+ + " Rebalance", false, true, false);
+ setLayout(layout);
+ taskInfo.setName(getId());
+ init();
+ }
+
+ private void init() {
+ ApplicationContext ctx = ContextLoader.getCurrentWebApplicationContext();
+ serverUtil = ctx.getBean(ServerUtil.class);
+ glusterUtil = ctx.getBean(GlusterInterfaceService.class);
+ }
+
+ @Override
+ public String getId() {
+ return new String(Base64.encode(getClusterName() + "-" + taskInfo.getType() + "-" + taskInfo.getReference()));
+ }
+
+ @Override
+ public void start() {
+ try {
+ serverName = getOnlineServer().getName();
+ startRebalance(serverName);
+ } catch (Exception e) {
+ // check if online server has gone offline. If yes, try again one more time.
+ if (e instanceof ConnectionException || serverUtil.isServerOnline(getOnlineServer()) == false) {
+ // online server might have gone offline. try with a new one
+ serverName = getNewOnlineServer().getName();
+ startRebalance(serverName);
+ } else {
+ throw new GlusterRuntimeException(e.getMessage());
+ }
+ }
+ }
+
+ private void startRebalance(String serverName) {
+ String command = "gluster volume rebalance " + getTaskInfo().getReference() + " " + getLayout() + " start";
+ String output = serverUtil.executeOnServer(serverName, command);
+ getTaskInfo().setStatus(new TaskStatus(new Status(Status.STATUS_CODE_RUNNING, output)));
+ }
+
+ @Override
+ public void resume() {
+ getTaskInfo().setStatus(
+ new TaskStatus(new Status(Status.STATUS_CODE_FAILURE,
+ "Pause/Resume is not supported in Volume Rebalance")));
+ }
+
+ @Override
+ public void stop() {
+ try {
+ glusterUtil.stopRebalance(serverName, getTaskInfo().getReference());
+ } catch (Exception e) {
+ // check if online server has gone offline. If yes, try again one more time.
+ if (e instanceof ConnectionException || serverUtil.isServerOnline(getOnlineServer()) == false) {
+ // online server might have gone offline. update the failure status
+ getTaskInfo().setStatus(new TaskStatus(new Status(Status.STATUS_CODE_FAILURE, e.getMessage())));
+ } else {
+ throw new GlusterRuntimeException(e.getMessage());
+ }
+ }
+ }
+
+ @Override
+ public void pause() {
+ getTaskInfo().setStatus(
+ new TaskStatus(new Status(Status.STATUS_CODE_FAILURE,
+ "Pause/Resume is not supported in Volume Rebalance")));
+ }
+
+ @Override
+ public TaskStatus checkStatus() {
+ try {
+ return glusterUtil.checkRebalanceStatus(serverName, getTaskInfo().getReference());
+ } catch (Exception e) {
+ // check if online server has gone offline. If yes, try again one more time.
+ if (e instanceof ConnectionException || serverUtil.isServerOnline(getOnlineServer()) == false) {
+ // online server might have gone offline. update the failure status
+ getTaskInfo().setStatus(new TaskStatus(new Status(Status.STATUS_CODE_FAILURE, e.getMessage())));
+ return getTaskInfo().getStatus();
+ }
+ }
+ return null;
+ }
+
+ public void setLayout(String layout) {
+ this.layout = layout;
+ }
+
+ public String getLayout() {
+ return layout;
+ }
+
+ @Override
+ public void commit() {
+ // TODO Auto-generated method stub
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/ServerSyncTask.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/ServerSyncTask.java
new file mode 100644
index 00000000..c3073d97
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/ServerSyncTask.java
@@ -0,0 +1,168 @@
+/**
+ * ServerDiscoveryTask.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 org.gluster.storage.management.gateway.tasks;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.gluster.storage.management.core.constants.CoreConstants;
+import org.gluster.storage.management.core.constants.GlusterConstants;
+import org.gluster.storage.management.core.model.GlusterServer;
+import org.gluster.storage.management.core.utils.GlusterCoreUtil;
+import org.gluster.storage.management.core.utils.ProcessResult;
+import org.gluster.storage.management.gateway.data.ClusterInfo;
+import org.gluster.storage.management.gateway.data.PersistenceDao;
+import org.gluster.storage.management.gateway.data.ServerInfo;
+import org.gluster.storage.management.gateway.services.ClusterService;
+import org.gluster.storage.management.gateway.services.DiscoveredServerService;
+import org.gluster.storage.management.gateway.services.GlusterServerService;
+import org.gluster.storage.management.gateway.utils.ServerUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+
+/**
+ * Task for syncing server details. This performs two things: <br>
+ * 1. Auto-discovery of servers eligible to be added to the Gluster cluster. <br>
+ * 2. Syncing of cluster-server mapping with actual servers of the cluster. This mapping can go out of sync if user
+ * adds/removes servers manually using the CLI.
+ */
+@Component
+public class ServerSyncTask {
+ private static final String SCRIPT_NAME_SFX = "-discover-servers.py";
+
+ @Autowired
+ private ServerUtil serverUtil;
+
+ @Autowired
+ private DiscoveredServerService discoveredServersService;
+
+ @Autowired
+ private GlusterServerService glusterServerService;
+
+ @Autowired
+ private String discoveryMechanism;
+
+ @Autowired
+ private ClusterService clusterService;
+
+ @Autowired
+ private PersistenceDao<ClusterInfo> clusterDao;
+
+ private static final Logger logger = Logger.getLogger(ServerSyncTask.class);
+
+ public void perform() {
+ discoverServers();
+ syncClusterServerMapping();
+ }
+
+ private void syncClusterServerMapping() {
+ List<ClusterInfo> clusters = clusterService.getAllClusters();
+ for(ClusterInfo cluster : clusters) {
+ try {
+ List<ServerInfo> servers = cluster.getServers();
+ if(servers.isEmpty()) {
+ logger.info("Cluster [" + cluster.getName() + "] is empty, nothing to sync!");
+ continue;
+ }
+ List<GlusterServer> actualServers = glusterServerService.getGlusterServers(cluster.getName(), false,
+ null, null);
+ updateRemovedServers(cluster, servers, actualServers);
+ updateAddedServers(cluster, servers, actualServers);
+ } catch(Exception e) {
+ // log error and continue with next cluster
+ logger.error("Couldn't sync cluster-server mapping for cluster [" + cluster.getName() + "]!", e);
+ continue;
+ }
+ }
+ }
+
+ private void updateAddedServers(ClusterInfo cluster, List<ServerInfo> servers, List<GlusterServer> actualServers) {
+ List<String> addedServers = findAddedServers(cluster.getName(), servers, actualServers);
+ for(String addedServer : addedServers) {
+ clusterService.mapServerToCluster(cluster.getName(), addedServer);
+ }
+ }
+
+ private void updateRemovedServers(ClusterInfo cluster, List<ServerInfo> servers, List<GlusterServer> actualServers) {
+ List<String> removedServers = findRemovedServers(servers, actualServers);
+ for(String removedServer : removedServers) {
+ clusterService.unmapServerFromCluster(cluster.getName(), removedServer);
+ }
+ }
+
+ private List<String> findRemovedServers(List<ServerInfo> servers, List<GlusterServer> actualServers) {
+ List<String> removedServers = new ArrayList<String>();
+
+ for(ServerInfo server : servers) {
+ if (!GlusterCoreUtil.containsEntityWithName(actualServers, server.getName(), true)) {
+ removedServers.add(server.getName());
+ }
+ }
+ return removedServers;
+ }
+
+ private List<String> findAddedServers(String clusterName, List<ServerInfo> servers, List<GlusterServer> actualServers) {
+ List<String> addedServers = new ArrayList<String>();
+ for(GlusterServer actualServer : actualServers) {
+ if(!serverExists(servers, actualServer.getName())) {
+ addedServers.add(actualServer.getName());
+ }
+ }
+ return addedServers;
+ }
+
+ private boolean serverExists(List<ServerInfo> servers, String name) {
+ for(ServerInfo server : servers) {
+ if(server.getName().equalsIgnoreCase(name)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @SuppressWarnings("unchecked")
+ private void discoverServers() {
+ if(discoveryMechanism.equals(GlusterConstants.NONE)) {
+ return;
+ }
+
+ List<String> serverNameList = new ArrayList<String>();
+
+ ProcessResult result = serverUtil.executeGlusterScript(true, discoveryMechanism + SCRIPT_NAME_SFX, new ArrayList<String>());
+ if(result.isSuccess()) {
+ List<String> existingServers = clusterDao.findBySQL("select name from server_info");
+ String serverNames = result.getOutput();
+ String[] parts = serverNames.split(CoreConstants.NEWLINE);
+ for(String serverName : parts) {
+ // The server discovery mechanism will return every server that has not been "peer probed". However we
+ // need to filter out those servers that are the "first" server of a new cluster, and hence are still
+ // not peer probed.
+ if(!existingServers.contains(serverName)) {
+ serverNameList.add(serverName);
+ }
+ }
+ }
+
+ discoveredServersService.setDiscoveredServerNames(serverNameList);
+ }
+} \ No newline at end of file
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/Task.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/Task.java
new file mode 100644
index 00000000..0fee3c2e
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/Task.java
@@ -0,0 +1,113 @@
+/**
+ * Task.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 org.gluster.storage.management.gateway.tasks;
+
+import org.gluster.storage.management.core.model.GlusterServer;
+import org.gluster.storage.management.core.model.TaskInfo;
+import org.gluster.storage.management.core.model.TaskStatus;
+import org.gluster.storage.management.core.model.TaskInfo.TASK_TYPE;
+import org.gluster.storage.management.gateway.services.ClusterService;
+
+
+public abstract class Task {
+ public String[] TASK_TYPE_STR = { "Format Disk", "Migrate Brick", "Volume Rebalance" };
+
+ protected TaskInfo taskInfo;
+ protected String clusterName;
+ private ClusterService clusterService;
+
+ public Task(ClusterService clusterService, String clusterName, TASK_TYPE type, String reference, String desc,
+ boolean canPause, boolean canStop, boolean canCommit) {
+ TaskInfo taskInfo = new TaskInfo();
+ taskInfo.setType(type);
+ taskInfo.setReference(reference);
+ taskInfo.setDescription(desc);
+ taskInfo.setPauseSupported(canPause);
+ taskInfo.setStopSupported(canStop);
+ taskInfo.setCommitSupported(canCommit);
+
+ init(clusterService, clusterName, taskInfo);
+
+ }
+
+ public Task(ClusterService clusterService, String clusterName, TaskInfo taskInfo) {
+ init(clusterService, clusterName, taskInfo);
+ }
+
+ private void init(ClusterService clusterService, String clusterName, TaskInfo taskInfo) {
+ this.clusterService = clusterService;
+ setClusterName(clusterName);
+ setTaskInfo(taskInfo);
+ }
+
+ protected GlusterServer getOnlineServer() {
+ return clusterService.getOnlineServer(clusterName);
+ }
+
+ protected GlusterServer getNewOnlineServer() {
+ return clusterService.getNewOnlineServer(clusterName);
+ }
+
+ protected GlusterServer getNewOnlineServer(String exceptServerName) {
+ return clusterService.getNewOnlineServer(clusterName, exceptServerName);
+ }
+
+ public String getTypeStr() {
+ return TASK_TYPE_STR[taskInfo.getType().ordinal()];
+ }
+
+ public TASK_TYPE getType() {
+ return getTaskInfo().getType();
+ }
+
+ public String getClusterName() {
+ return clusterName;
+ }
+
+ public void setClusterName(String clusterName) {
+ this.clusterName = clusterName;
+ }
+
+ public TaskInfo getTaskInfo() {
+ return taskInfo;
+ }
+
+ public void setTaskInfo(TaskInfo info) {
+ this.taskInfo = info;
+ }
+
+ public abstract String getId();
+
+ public abstract void start();
+
+ public abstract void resume();
+
+ public abstract void stop();
+
+ public abstract void pause();
+
+ public abstract void commit();
+
+ /**
+ * This method should check current status of the task and update it's taskInfo accordingly
+ */
+ public abstract TaskStatus checkStatus();
+}