summaryrefslogtreecommitdiffstats
path: root/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/services/GlusterServerService.java
diff options
context:
space:
mode:
authorShireesh Anjal <shireesh@gluster.com>2011-08-19 13:40:09 +0530
committerShireesh Anjal <shireesh@gluster.com>2011-08-19 13:40:09 +0530
commitf0412952e8a0e67f134d96963f8b9e3e8b4738c6 (patch)
treef06e522d48d5d7f4aea1454d19cb4c81443ec200 /src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/services/GlusterServerService.java
parent9fdc4e3e7213544a4813e81ac778e38747f9b002 (diff)
Introduced DiscoveredServerService, and fetching discovered server details in parallel through multiple threads to improve performance.
Diffstat (limited to 'src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/services/GlusterServerService.java')
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/services/GlusterServerService.java198
1 files changed, 141 insertions, 57 deletions
diff --git a/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/services/GlusterServerService.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/services/GlusterServerService.java
index 7d5f0fff..f69b4a75 100644
--- a/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/services/GlusterServerService.java
+++ b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/services/GlusterServerService.java
@@ -18,10 +18,11 @@
*******************************************************************************/
package com.gluster.storage.management.gateway.services;
+import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_SERVER_NAME;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import java.util.Vector;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
@@ -35,11 +36,12 @@ import com.gluster.storage.management.core.model.GlusterServer;
import com.gluster.storage.management.core.model.Server;
import com.gluster.storage.management.core.model.Server.SERVER_STATUS;
import com.gluster.storage.management.core.utils.GlusterCoreUtil;
+import com.gluster.storage.management.core.utils.ProcessUtil;
import com.gluster.storage.management.gateway.data.ClusterInfo;
import com.gluster.storage.management.gateway.data.ServerInfo;
-import com.gluster.storage.management.gateway.resources.v1_0.DiscoveredServersResource;
import com.gluster.storage.management.gateway.utils.GlusterUtil;
import com.gluster.storage.management.gateway.utils.ServerUtil;
+import com.gluster.storage.management.gateway.utils.SshUtil;
/**
*
@@ -56,11 +58,15 @@ public class GlusterServerService {
private GlusterUtil glusterUtil;
@Autowired
+ private SshUtil sshUtil;
+
+ @Autowired
private VolumeService volumeService;
- // TODO: create a discovered servers "service" instead of injecting the resource directly
@Autowired
- private DiscoveredServersResource discoveredServersResource;
+ private DiscoveredServerService discoveredServerService;
+
+ private static final Logger logger = Logger.getLogger(GlusterServerService.class);
public void fetchServerDetails(GlusterServer server) {
try {
@@ -121,7 +127,7 @@ public class GlusterServerService {
glusterServers = GlusterCoreUtil.skipEntities(glusterServers, maxCount, previousServerName);
if (fetchDetails) {
- String errMsg = fetchDetailsOfServers(glusterServers);
+ String errMsg = fetchDetailsOfServers(Collections.synchronizedList(glusterServers));
if (!errMsg.isEmpty()) {
throw new GlusterRuntimeException("Couldn't fetch details for server(s): " + errMsg);
}
@@ -131,10 +137,16 @@ public class GlusterServerService {
private String fetchDetailsOfServers(List<GlusterServer> glusterServers) {
try {
- return new ServerDetailsThread(glusterServers).fetchDetails();
+ List<String> errors = Collections.synchronizedList(new ArrayList<String>());
+
+ List<Thread> threads = createThreads(glusterServers, errors);
+ ProcessUtil.waitForThreads(threads);
+
+ return prepareErrorMessage(errors);
} catch(InterruptedException e) {
- throw new GlusterRuntimeException("Exception while fetching details of servers! Error: [" + e.getMessage()
- + "]", e);
+ String errMsg = "Exception while fetching details of servers! Error: [" + e.getMessage() + "]";
+ logger.error(errMsg, e);
+ throw new GlusterRuntimeException(errMsg, e);
}
// String errMsg = "";
//
@@ -147,66 +159,56 @@ public class GlusterServerService {
// }
// return errMsg;
}
-
+
+ private String prepareErrorMessage(List<String> errors) {
+ String errMsg = "";
+ for(String error : errors) {
+ if(!errMsg.isEmpty()) {
+ errMsg += CoreConstants.NEWLINE;
+ }
+ errMsg += error;
+ }
+
+ return errMsg;
+ }
+
+ /**
+ * Creates threads that will run in parallel and fetch details of given gluster servers
+ * @param discoveredServers The list to be populated with details of gluster servers
+ * @param errors List to be populated with errors if any
+ * @return
+ * @throws InterruptedException
+ */
+ private List<Thread> createThreads(List<GlusterServer> glusterServers, List<String> errors)
+ throws InterruptedException {
+ List<Thread> threads = new ArrayList<Thread>();
+ for (int i = glusterServers.size()-1; i >= 0 ; i--) {
+ Thread thread = new ServerDetailsThread(glusterServers.get(i), errors);
+ threads.add(thread);
+ thread.start();
+ if(i >= 5 && i % 5 == 0) {
+ // After every 5 servers, wait for 1 second so that we don't end up with too many running threads
+ Thread.sleep(1000);
+ }
+ }
+ return threads;
+ }
+
public class ServerDetailsThread extends Thread {
private List<String> errors;
- private List<GlusterServer> glusterServers;
private GlusterServer server;
private final Logger logger = Logger.getLogger(ServerDetailsThread.class);
/**
- * This constructor should be called by clients that need to fetch details of the servers in parallel
- * @param glusterServers
- */
- public ServerDetailsThread(List<GlusterServer> glusterServers) {
- // create a synchronized "copy" so that the original list remains untouched
- this(Collections.synchronizedList(new ArrayList<GlusterServer>(glusterServers)), Collections
- .synchronizedList(new ArrayList<String>()), null);
- }
-
- /**
* Private constructor called on each thread
- * @param glusterServers
+ * @param server The server whose details are to be fetched by this thread
* @param errors
*/
- private ServerDetailsThread(List<GlusterServer> glusterServers, List<String> errors, GlusterServer server) {
- this.glusterServers = glusterServers;
+ private ServerDetailsThread(GlusterServer server, List<String> errors) {
this.errors = errors;
this.server = server;
}
- /**
- * Call this method to fetch details of all the servers passed in the constructor. Internally creates one thread
- * for each server
- *
- * @param glusterServers
- * @return
- */
- public String fetchDetails() throws InterruptedException {
- for (int i = glusterServers.size()-1; i >= 0 ; i--) {
- new ServerDetailsThread(glusterServers, errors, glusterServers.get(i)).start();
- if(i >= 5 && i % 5 == 0) {
- // After every 5 servers, wait for 1 second so that we don't end up with too many running threads
- Thread.sleep(1000);
- }
- }
-
- // Wait till all servers have been processed
- while (!glusterServers.isEmpty()) {
- Thread.sleep(500);
- }
-
- String errMsg = "";
- for(String error : errors) {
- if(!errMsg.isEmpty()) {
- errMsg += CoreConstants.NEWLINE;
- }
- errMsg += error;
- }
-
- return errMsg;
- }
-
@Override
public void run() {
try {
@@ -217,7 +219,6 @@ public class GlusterServerService {
logger.error("fetching details of server [" + server.getName() + "] - error", e);
errors.add(server.getName() + " : [" + e.getMessage() + "]");
}
- glusterServers.remove(server);
}
}
@@ -340,7 +341,7 @@ public class GlusterServerService {
// since the server is removed from the cluster, it is now available to be added to other clusters.
// Hence add it back to the discovered servers list.
- discoveredServersResource.addDiscoveredServer(serverName);
+ discoveredServerService.addDiscoveredServer(serverName);
}
clusterService.unmapServerFromCluster(clusterName, serverName);
@@ -354,4 +355,87 @@ public class GlusterServerService {
}
return false;
}
+
+ /**
+ * Adds given server to cluster and returns its host name. e.g. If serverName passed is an IP address, this method
+ * will return the host name of the machine with given IP address.
+ *
+ * @param clusterName
+ * @param serverName
+ * @return
+ */
+ public String addServerToCluster(String clusterName, String serverName) {
+ if (clusterName == null || clusterName.isEmpty()) {
+ throw new GlusterValidationException("Cluster name must not be empty!");
+ }
+
+ if (serverName == null || serverName.isEmpty()) {
+ throw new GlusterValidationException("Parameter [" + FORM_PARAM_SERVER_NAME + "] is missing in request!");
+ }
+
+ ClusterInfo cluster = clusterService.getCluster(clusterName);
+ if (cluster == null) {
+ throw new GlusterValidationException("Cluster [" + clusterName + "] not found!");
+ }
+
+ boolean publicKeyInstalled = sshUtil.isPublicKeyInstalled(serverName);
+ if (!publicKeyInstalled && !sshUtil.hasDefaultPassword(serverName)) {
+ // public key not installed, default password doesn't work. return with error.
+ throw new GlusterRuntimeException("Gluster Management Gateway uses the default password to set up keys on the server."
+ + CoreConstants.NEWLINE + "However it seems that the password on server [" + serverName
+ + "] has been changed manually." + CoreConstants.NEWLINE
+ + "Please reset it back to the standard default password and try again.");
+ }
+
+ String hostName = serverUtil.fetchHostName(serverName);
+ List<ServerInfo> servers = cluster.getServers();
+ if (servers != null && !servers.isEmpty()) {
+ // cluster has at least one existing server, so that peer probe can be performed
+ performAddServer(clusterName, hostName);
+ } else {
+ // this is the first server to be added to the cluster, which means no
+ // gluster CLI operation required. just add it to the cluster-server mapping
+ }
+
+ // add the cluster-server mapping
+ clusterService.mapServerToCluster(clusterName, hostName);
+
+ // since the server is added to a cluster, it should not more be considered as a
+ // discovered server available to other clusters
+ discoveredServerService.removeDiscoveredServer(hostName);
+
+ if (!publicKeyInstalled) {
+ try {
+ // install public key (this will also disable password based ssh login)
+ sshUtil.installPublicKey(hostName);
+ } catch (Exception e) {
+ throw new GlusterRuntimeException("Public key could not be installed on [" + hostName + "]! Error: ["
+ + e.getMessage() + "]");
+ }
+ }
+ return hostName;
+ }
+
+ private void performAddServer(String clusterName, String serverName) {
+ GlusterServer onlineServer = clusterService.getOnlineServer(clusterName);
+ if (onlineServer == null) {
+ throw new GlusterRuntimeException("No online server found in cluster [" + clusterName + "]");
+ }
+
+ try {
+ glusterUtil.addServer(onlineServer.getName(), serverName);
+ } catch (Exception e) {
+ // check if online server has gone offline. If yes, try again one more time.
+ if (e instanceof ConnectionException || serverUtil.isServerOnline(onlineServer) == false) {
+ // online server has gone offline! try with a different one.
+ onlineServer = clusterService.getNewOnlineServer(clusterName);
+ if (onlineServer == null) {
+ throw new GlusterRuntimeException("No online server found in cluster [" + clusterName + "]");
+ }
+ glusterUtil.addServer(onlineServer.getName(), serverName);
+ } else {
+ throw new GlusterRuntimeException(e.getMessage());
+ }
+ }
+ }
}