diff options
| author | Tim <timothyasir@gluster.com> | 2011-07-01 14:47:05 +0530 |
|---|---|---|
| committer | Tim <timothyasir@gluster.com> | 2011-07-01 14:47:05 +0530 |
| commit | 9cdc7095308011332392ddd040b34106ef3abd6a (patch) | |
| tree | a4b6d72ef81611be53bf46f940cd8ff70eadbf15 /src/com.gluster.storage.management.server | |
| parent | 19ed9b4866499d9c264c8db8fc616fb5a5e36ce3 (diff) | |
| parent | 40d4024c47ca1e1e15e2500a5412791d364bd8b0 (diff) | |
Merge remote branch 'upstream/master'
Diffstat (limited to 'src/com.gluster.storage.management.server')
18 files changed, 1127 insertions, 452 deletions
diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/AbstractResource.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/AbstractResource.java index ee65add0..feef8b3e 100644 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/AbstractResource.java +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/AbstractResource.java @@ -65,21 +65,32 @@ public class AbstractResource { * Creates a response with HTTP status code of 202 (accepted), also setting the location header to given location. * This is typically done while triggering long running tasks * - * @param uriElements - * URI Elements to be appended to the base URI + * @param locationURI + * URI to be appended to the base URI * @return the {@link Response} object */ - protected Response acceptedResponse(Object...uriElements) { - return Response.status(Status.ACCEPTED).location(createAbsoluteURI(uriElements)).build(); + protected Response acceptedResponse(String locationURI) { + return Response.status(Status.ACCEPTED).location(createAbsoluteURI(locationURI)).build(); + } + + /** + * Creates a response with HTTP status code of 404 (not found), also setting the given message in the response body + * + * @param message + * Message to be set in the response body + * @return the {@link Response} object + */ + protected Response notFoundResponse(String message) { + return Response.status(Status.NOT_FOUND).type(MediaType.TEXT_HTML).entity(message).build(); } /** * Creates a new URI that is relative to the <b>base URI</b> of the application - * @param uriElements URI Elements to be appended to the base URI + * @param uriString URI String to be appended to the base URI * @return newly created URI */ - private URI createAbsoluteURI(Object[] uriElements) { - return uriInfo.getBaseUriBuilder().build(uriElements); + private URI createAbsoluteURI(String uriString) { + return uriInfo.getBaseUriBuilder().path(uriString).build(); } /** @@ -123,6 +134,15 @@ public class AbstractResource { protected Response badRequestResponse(String errMessage) { return Response.status(Status.BAD_REQUEST).type(MediaType.TEXT_HTML).entity(errMessage).build(); } + + /** + * Creates a response with HTTP status code of 401 (unauthorized) + * + * @return the {@link Response} object + */ + protected Response unauthorizedResponse() { + return Response.status(Status.UNAUTHORIZED).build(); + } /** * Creates an OK response and sets the entity in the response body. @@ -138,6 +158,17 @@ public class AbstractResource { } /** + * Creates an OK response without any entity in the response body. + * + * @param mediaType + * Media type to be set on the response + * @return the {@link Response} object + */ + protected Response okResponse(String mediaType) { + return Response.ok().type(mediaType).build(); + } + + /** * Creates a streaming output response and sets the given streaming output in the response. Typically used for * "download" requests * diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/AbstractServersResource.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/AbstractServersResource.java index 0bc0f061..dd6e2804 100644 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/AbstractServersResource.java +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/AbstractServersResource.java @@ -20,9 +20,6 @@ */ package com.gluster.storage.management.server.resources; -import com.gluster.storage.management.core.exceptions.GlusterRuntimeException; -import com.gluster.storage.management.core.model.Server; -import com.gluster.storage.management.core.model.Status; import com.gluster.storage.management.server.utils.GlusterUtil; import com.gluster.storage.management.server.utils.ServerUtil; import com.sun.jersey.api.core.InjectParam; @@ -37,19 +34,5 @@ public class AbstractServersResource extends AbstractResource { @InjectParam protected GlusterUtil glusterUtil; - /** - * Fetch details of the given server. The server name must be populated in the object before calling this method. - * - * @param server - * Server whose details are to be fetched - */ - protected void fetchServerDetails(Server server) { - // fetch standard server details like cpu, disk, memory details - Object response = serverUtil.executeOnServer(true, server.getName(), "get_server_details.py --only-data-disks", Server.class); - if (response instanceof Status) { - // TODO: check if this happened because the server is not reachable, and if yes, set it's status as offline - throw new GlusterRuntimeException(((Status)response).getMessage()); - } - server.copyFrom((Server) response); // Update the details in <Server> object - } + // TODO: Remove this class! } diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/ClustersResource.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/ClustersResource.java index 2ce23a4e..4c834973 100644 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/ClustersResource.java +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/ClustersResource.java @@ -106,7 +106,6 @@ public class ClustersResource extends AbstractResource { return badRequestResponse("Server [" + knownServer + "] is already present in cluster [" + mappedCluster.getName() + "]!"); } - try { clusterService.registerCluster(clusterName, knownServer); diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/DiscoveredServersResource.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/DiscoveredServersResource.java index aba88d82..283ab147 100644 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/DiscoveredServersResource.java +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/DiscoveredServersResource.java @@ -18,6 +18,8 @@ *******************************************************************************/ package com.gluster.storage.management.server.resources; +import static com.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_SERVER_NAME; +import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_DETAILS; import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_PATH_DISCOVERED_SERVERS; import java.util.ArrayList; @@ -29,16 +31,13 @@ import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; import org.springframework.stereotype.Component; -import com.gluster.storage.management.core.constants.CoreConstants; -import com.gluster.storage.management.core.model.Response; import com.gluster.storage.management.core.model.Server; -import com.gluster.storage.management.core.model.Status; -import com.gluster.storage.management.core.response.GenericResponse; import com.gluster.storage.management.core.response.ServerListResponse; -import com.gluster.storage.management.core.response.StringListResponse; +import com.gluster.storage.management.core.response.ServerNameListResponse; import com.sun.jersey.spi.resource.Singleton; @Component @@ -67,57 +66,76 @@ public class DiscoveredServersResource extends AbstractServersResource { @GET @Produces(MediaType.APPLICATION_XML) - @SuppressWarnings("rawtypes") - public Response getDiscoveredServers(@QueryParam("details") Boolean getDetails) { - if(getDetails != null && getDetails == true) { - return getDiscoveredServerDetails(); + public Response getDiscoveredServersXML(@QueryParam(QUERY_PARAM_DETAILS) Boolean details) { + return getDiscoveredServersResponse(details, MediaType.APPLICATION_XML); + } + + @GET + @Produces(MediaType.APPLICATION_JSON) + public Response getDiscoveredServersJSON(@QueryParam(QUERY_PARAM_DETAILS) Boolean details) { + return getDiscoveredServersResponse(details, MediaType.APPLICATION_JSON); + } + + private Response getDiscoveredServersResponse(Boolean details, String mediaType) { + if(details != null && details == true) { + try { + List<Server> discoveredServers = getDiscoveredServerDetails(); + return okResponse(new ServerListResponse(discoveredServers), mediaType); + } catch(Exception e) { + return errorResponse(e.getMessage()); + } + } else { + return okResponse(new ServerNameListResponse(getDiscoveredServerNames()), mediaType); } - return new StringListResponse(getDiscoveredServerNames()); } - private ServerListResponse getDiscoveredServerDetails() { + private List<Server> getDiscoveredServerDetails() { List<Server> discoveredServers = new ArrayList<Server>(); - List<String> serverNames = getDiscoveredServerNames(); - GenericResponse<Server> discoveredServerResponse; - int errCount = 0; - StringBuilder errMsg = new StringBuilder("Couldn't fetch details for server(s): "); - for (String serverName : serverNames) { - discoveredServerResponse = getDiscoveredServer(serverName); - if (!discoveredServerResponse.getStatus().isSuccess()) { - errMsg.append(CoreConstants.NEWLINE + serverName + " : " + discoveredServerResponse.getStatus()); - errCount++; - } else { - discoveredServers.add(discoveredServerResponse.getData()); + for (String serverName : getDiscoveredServerNames()) { + try { + discoveredServers.add(getDiscoveredServer(serverName)); + } catch(Exception e) { + // TODO: Log the exception + // continue with next discovered server } } - Status status = null; - if(errCount == 0) { - status = new Status(Status.STATUS_CODE_SUCCESS, "Success"); - } else if(errCount == serverNames.size()) { - status = new Status(Status.STATUS_CODE_FAILURE, errMsg.toString()); - } else { - status = new Status(Status.STATUS_CODE_PART_SUCCESS, errMsg.toString()); - } - return new ServerListResponse(status, discoveredServers); + return discoveredServers; } - @Path("/{serverName}") + @Path("{" + PATH_PARAM_SERVER_NAME + "}") @GET @Produces(MediaType.APPLICATION_XML) - public GenericResponse<Server> getDiscoveredServer(@PathParam("serverName") String serverName) { - Server server = new Server(serverName); + public Response getDiscoveredServerXML(@PathParam(PATH_PARAM_SERVER_NAME) String serverName) { + return getDiscoveredServerResponse(serverName, MediaType.APPLICATION_XML); + } + + @Path("{" + PATH_PARAM_SERVER_NAME + "}") + @GET + @Produces(MediaType.APPLICATION_JSON) + public Response getDiscoveredServerJSON(@PathParam(PATH_PARAM_SERVER_NAME) String serverName) { + return getDiscoveredServerResponse(serverName, MediaType.APPLICATION_JSON); + } + + private Response getDiscoveredServerResponse(String serverName, String mediaType) { + if(serverName == null || serverName.isEmpty()) { + return badRequestResponse("Server name must not be empty!"); + } try { - fetchServerDetails(server); + return okResponse(getDiscoveredServer(serverName), mediaType); } catch (Exception e) { - return new GenericResponse<Server>(new Status(e), null); + // TODO: Log the exception + return errorResponse(e.getMessage()); } - return new GenericResponse<Server>(Status.STATUS_SUCCESS, server); + } + + private Server getDiscoveredServer(String serverName) { + Server server = new Server(serverName); + serverUtil.fetchServerDetails(server); + return server; } public static void main(String[] args) { - StringListResponse listResponse = (StringListResponse)new DiscoveredServersResource().getDiscoveredServers(false); - for (String server : listResponse.getData()) { - System.out.println(server); - } + Response response = (Response)new DiscoveredServersResource().getDiscoveredServersXML(false); + System.out.println(response.getEntity()); } } diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/GlusterServersResource.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/GlusterServersResource.java index 6e15e106..a9ef7fbb 100644 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/GlusterServersResource.java +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/GlusterServersResource.java @@ -18,13 +18,14 @@ *******************************************************************************/ package com.gluster.storage.management.server.resources; -import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_CLUSTER_NAME; import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_SERVER_NAME; -import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_SOURCE; import static com.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_CLUSTER_NAME; +import static com.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_DISK_NAME; import static com.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_SERVER_NAME; +import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_DISKS; import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_PATH_CLUSTERS; import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_SERVERS; +import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_TASKS; import java.util.ArrayList; import java.util.List; @@ -33,6 +34,7 @@ import javax.ws.rs.DELETE; import javax.ws.rs.FormParam; import javax.ws.rs.GET; import javax.ws.rs.POST; +import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; @@ -43,17 +45,16 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.gluster.storage.management.core.constants.CoreConstants; +import com.gluster.storage.management.core.constants.RESTConstants; import com.gluster.storage.management.core.exceptions.ConnectionException; import com.gluster.storage.management.core.exceptions.GlusterRuntimeException; 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.response.GlusterServerListResponse; -import com.gluster.storage.management.core.response.GlusterServerResponse; -import com.gluster.storage.management.core.utils.LRUCache; import com.gluster.storage.management.server.data.ClusterInfo; import com.gluster.storage.management.server.data.ServerInfo; import com.gluster.storage.management.server.services.ClusterService; +import com.gluster.storage.management.server.tasks.InitializeDiskTask; import com.gluster.storage.management.server.utils.GlusterUtil; import com.gluster.storage.management.server.utils.SshUtil; import com.sun.jersey.api.core.InjectParam; @@ -65,128 +66,90 @@ import com.sun.jersey.spi.resource.Singleton; public class GlusterServersResource extends AbstractServersResource { public static final String HOSTNAMETAG = "hostname:"; - private LRUCache<String, GlusterServer> clusterServerCache = new LRUCache<String, GlusterServer>(3); - + @InjectParam private DiscoveredServersResource discoveredServersResource; - + + @InjectParam + private TasksResource taskResource; + @Autowired private ClusterService clusterService; - + @Autowired private SshUtil sshUtil; - + protected void fetchServerDetails(GlusterServer server) { try { server.setStatus(SERVER_STATUS.ONLINE); - super.fetchServerDetails(server); - } catch(ConnectionException e) { + serverUtil.fetchServerDetails(server); + } catch (ConnectionException e) { server.setStatus(SERVER_STATUS.OFFLINE); } } - - public GlusterServer getOnlineServer(String clusterName) { - return getOnlineServer(clusterName, ""); - } - - // uses cache - public GlusterServer getOnlineServer(String clusterName, String exceptServerName) { - GlusterServer server = clusterServerCache.get(clusterName); - if(server != null && !server.getName().equals(exceptServerName)) { - return server; - } - - return getNewOnlineServer(clusterName, exceptServerName); - } - public GlusterServer getNewOnlineServer(String clusterName) { - return getNewOnlineServer(clusterName, ""); - } - // Doesn't use cache - public GlusterServer getNewOnlineServer(String clusterName, String exceptServerName) { - ClusterInfo cluster = clusterService.getCluster(clusterName); - if(cluster == null) { - return null; - } - - for(ServerInfo serverInfo : cluster.getServers()) { - GlusterServer server = new GlusterServer(serverInfo.getName()); - fetchServerDetails(server); - if(server.isOnline() && !server.getName().equals(exceptServerName)) { - // server is online. add it to cache and return - clusterServerCache.put(clusterName, server); - return server; - } - } - - // no online server found. - return null; - } - @GET @Produces(MediaType.APPLICATION_JSON) - public Response getGlusterServersJSON( - @PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName) { + public Response getGlusterServersJSON(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName) { return getGlusterServers(clusterName, MediaType.APPLICATION_JSON); } @GET @Produces(MediaType.APPLICATION_XML) - public Response getGlusterServersXML( - @PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName) { + public Response getGlusterServersXML(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName) { return getGlusterServers(clusterName, MediaType.APPLICATION_XML); } public Response getGlusterServers(String clusterName, String mediaType) { List<GlusterServer> glusterServers = new ArrayList<GlusterServer>(); - + if (clusterName == null || clusterName.isEmpty()) { return badRequestResponse("Cluster name must not be empty!"); } ClusterInfo cluster = clusterService.getCluster(clusterName); if (cluster == null) { - return badRequestResponse("Cluster [" + clusterName + "] not found!"); + return notFoundResponse("Cluster [" + clusterName + "] not found!"); } - if(cluster.getServers().size() == 0) { + if (cluster.getServers().size() == 0) { return okResponse(new GlusterServerListResponse(glusterServers), mediaType); } - - GlusterServer onlineServer = getOnlineServer(clusterName); + + GlusterServer onlineServer = clusterService.getOnlineServer(clusterName); if (onlineServer == null) { return errorResponse("No online servers found in cluster [" + clusterName + "]"); } - + try { glusterServers = getGlusterServers(clusterName, onlineServer); - } catch(ConnectionException e) { + } catch (ConnectionException e) { // online server has gone offline! try with a different one. - onlineServer = getNewOnlineServer(clusterName); + onlineServer = clusterService.getNewOnlineServer(clusterName); if (onlineServer == null) { return errorResponse("No online servers found in cluster [" + clusterName + "]"); } try { glusterServers = getGlusterServers(clusterName, onlineServer); - } catch(Exception e1) { + } catch (Exception e1) { return errorResponse(e1.getMessage()); } - } catch(Exception e) { + } catch (Exception e) { return errorResponse(e.getMessage()); } - + String errMsg = fetchDetailsOfServers(glusterServers, onlineServer); - if(!errMsg.isEmpty()) { + if (!errMsg.isEmpty()) { return errorResponse("Couldn't fetch details for server(s): " + errMsg); } - + return okResponse(new GlusterServerListResponse(glusterServers), mediaType); } public String fetchDetailsOfServers(List<GlusterServer> glusterServers, GlusterServer onlineServer) { String errMsg = ""; - + for (GlusterServer server : glusterServers) { if (server.getStatus() == SERVER_STATUS.ONLINE && !server.getName().equals(onlineServer.getName())) { try { @@ -203,13 +166,13 @@ public class GlusterServersResource extends AbstractServersResource { List<GlusterServer> glusterServers; try { glusterServers = glusterUtil.getGlusterServers(onlineServer); - } catch(ConnectionException e) { + } catch (ConnectionException e) { // online server has gone offline! try with a different one. - onlineServer = getNewOnlineServer(clusterName); - if(onlineServer == null) { + onlineServer = clusterService.getNewOnlineServer(clusterName); + if (onlineServer == null) { throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]"); } - + glusterServers = glusterUtil.getGlusterServers(onlineServer); } return glusterServers; @@ -218,8 +181,7 @@ public class GlusterServersResource extends AbstractServersResource { @GET @Path("{serverName}") @Produces(MediaType.APPLICATION_XML) - public Response getGlusterServerXML( - @PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName, + public Response getGlusterServerXML(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName, @PathParam(PATH_PARAM_SERVER_NAME) String serverName) { return getGlusterServerResponse(clusterName, serverName, MediaType.APPLICATION_XML); } @@ -227,8 +189,7 @@ public class GlusterServersResource extends AbstractServersResource { @GET @Path("{serverName}") @Produces(MediaType.APPLICATION_JSON) - public Response getGlusterServerJSON( - @PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName, + public Response getGlusterServerJSON(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName, @PathParam(PATH_PARAM_SERVER_NAME) String serverName) { return getGlusterServerResponse(clusterName, serverName, MediaType.APPLICATION_JSON); } @@ -236,7 +197,7 @@ public class GlusterServersResource extends AbstractServersResource { private Response getGlusterServerResponse(String clusterName, String serverName, String mediaType) { try { return okResponse(getGlusterServer(clusterName, serverName), mediaType); - } catch(Exception e) { + } catch (Exception e) { return errorResponse(e.getMessage()); } } @@ -255,93 +216,93 @@ public class GlusterServersResource extends AbstractServersResource { throw new GlusterRuntimeException("Cluster [" + clusterName + "] not found!"); } - GlusterServer onlineServer = getOnlineServer(clusterName); + GlusterServer onlineServer = clusterService.getOnlineServer(clusterName); if (onlineServer == null) { throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]"); } - + GlusterServer server = null; try { server = glusterUtil.getGlusterServer(onlineServer, serverName); - } catch(ConnectionException e) { + } catch (ConnectionException e) { // online server has gone offline! try with a different one. - onlineServer = getNewOnlineServer(clusterName); + onlineServer = clusterService.getNewOnlineServer(clusterName); if (onlineServer == null) { throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]"); } server = glusterUtil.getGlusterServer(onlineServer, serverName); } - - if(server.isOnline()) { + + if (server.isOnline()) { fetchServerDetails(server); } return server; } private void performAddServer(String clusterName, String serverName) { - GlusterServer onlineServer = getOnlineServer(clusterName); - if(onlineServer == null) { + 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(ConnectionException e) { + } catch (ConnectionException e) { // online server has gone offline! try with a different one. - onlineServer = getNewOnlineServer(clusterName); - if(onlineServer == null) { + onlineServer = clusterService.getNewOnlineServer(clusterName); + if (onlineServer == null) { throw new GlusterRuntimeException("No online server found in cluster [" + clusterName + "]"); } - + glusterUtil.addServer(serverName, onlineServer.getName()); } } - + @POST public Response addServer(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName, @FormParam(FORM_PARAM_SERVER_NAME) String serverName) { - if(clusterName == null || clusterName.isEmpty()) { + if (clusterName == null || clusterName.isEmpty()) { return badRequestResponse("Cluster name must not be empty!"); } - - if(serverName == null || serverName.isEmpty()) { + + if (serverName == null || serverName.isEmpty()) { return badRequestResponse("Parameter [" + FORM_PARAM_SERVER_NAME + "] is missing in request!"); } - + ClusterInfo cluster = clusterService.getCluster(clusterName); if (cluster == null) { - return badRequestResponse("Cluster [" + clusterName + "] not found!"); + return notFoundResponse("Cluster [" + clusterName + "] not found!"); } - + boolean publicKeyInstalled = sshUtil.isPublicKeyInstalled(serverName); - if(!publicKeyInstalled && !sshUtil.hasDefaultPassword(serverName)) { + if (!publicKeyInstalled && !sshUtil.hasDefaultPassword(serverName)) { // public key not installed, default password doesn't work. return with error. return errorResponse("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."); } - + List<ServerInfo> servers = cluster.getServers(); - if(servers != null && !servers.isEmpty()) { + if (servers != null && !servers.isEmpty()) { // cluster has at least one existing server, so that peer probe can be performed try { performAddServer(clusterName, serverName); - } catch(Exception e) { + } catch (Exception e) { return errorResponse(e.getMessage()); } } 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 } - + try { // add the cluster-server mapping clusterService.mapServerToCluster(clusterName, serverName); } catch (Exception e) { return errorResponse(e.getMessage()); } - + // since the server is added to a cluster, it should not more be considered as a // discovered server available to other clusters discoveredServersResource.removeDiscoveredServer(serverName); @@ -366,40 +327,39 @@ public class GlusterServersResource extends AbstractServersResource { if (clusterName == null || clusterName.isEmpty()) { return badRequestResponse("Cluster name must not be empty!"); } - - if(serverName == null || serverName.isEmpty()) { + + if (serverName == null || serverName.isEmpty()) { return badRequestResponse("Server name must not be empty!"); } - + ClusterInfo cluster = clusterService.getCluster(clusterName); - if(cluster == null) { - return badRequestResponse("Cluster [" + clusterName + "] not found!"); + if (cluster == null) { + return notFoundResponse("Cluster [" + clusterName + "] not found!"); } List<ServerInfo> servers = cluster.getServers(); - if(servers == null || servers.isEmpty() || !containsServer(servers, serverName)) { - return badRequestResponse("Server [" + serverName + "] is not attached to cluster [" - + clusterName + "]!"); + if (servers == null || servers.isEmpty() || !containsServer(servers, serverName)) { + return badRequestResponse("Server [" + serverName + "] is not attached to cluster [" + clusterName + "]!"); } - - if(servers.size() == 1) { + + if (servers.size() == 1) { // Only one server mapped to the cluster, no "peer detach" required. // remove the cached online server for this cluster if present - clusterServerCache.remove(clusterName); + clusterService.removeOnlineServer(clusterName); } else { try { removeServerFromCluster(clusterName, serverName); - } catch(Exception e) { + } catch (Exception e) { return errorResponse(e.getMessage()); } - } - + } + return noContentResponse(); } - + private void removeServerFromCluster(String clusterName, String serverName) { // get an online server that is not same as the server being removed - GlusterServer onlineServer = getOnlineServer(clusterName, serverName); + GlusterServer onlineServer = clusterService.getOnlineServer(clusterName, serverName); if (onlineServer == null) { throw new GlusterRuntimeException("No online server found in cluster [" + clusterName + "]"); } @@ -408,34 +368,63 @@ public class GlusterServersResource extends AbstractServersResource { glusterUtil.removeServer(onlineServer.getName(), serverName); } catch (ConnectionException e) { // online server has gone offline! try with a different one. - onlineServer = getNewOnlineServer(clusterName, serverName); + onlineServer = clusterService.getNewOnlineServer(clusterName, serverName); if (onlineServer == null) { throw new GlusterRuntimeException("No online server found in cluster [" + clusterName + "]"); } glusterUtil.removeServer(onlineServer.getName(), serverName); } - - if(onlineServer.getName().equals(serverName)) { + + if (onlineServer.getName().equals(serverName)) { // since the cached server has been removed from the cluster, remove it from the cache - clusterServerCache.remove(clusterName); + clusterService.removeOnlineServer(clusterName); } - + clusterService.unmapServerFromCluster(clusterName, serverName); - - // since the server is removed from the cluster, it is now available to be added to other clusters. + + // 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); + discoveredServersResource.addDiscoveredServer(serverName); } private boolean containsServer(List<ServerInfo> servers, String serverName) { - for(ServerInfo server : servers) { - if(server.getName().toUpperCase().equals(serverName.toUpperCase())) { + for (ServerInfo server : servers) { + if (server.getName().toUpperCase().equals(serverName.toUpperCase())) { return true; } } return false; } + @PUT + @Produces(MediaType.APPLICATION_XML) + @Path("{" + PATH_PARAM_SERVER_NAME + "}/" + RESOURCE_DISKS + "/{" + PATH_PARAM_DISK_NAME + "}") + public Response initializeDisk(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName, + @PathParam(PATH_PARAM_SERVER_NAME) String serverName, @PathParam(PATH_PARAM_DISK_NAME) String diskName) { + + if (clusterName == null || clusterName.isEmpty()) { + return badRequestResponse("Cluster name must not be empty!"); + } + + if (serverName == null || serverName.isEmpty()) { + return badRequestResponse("Server name must not be empty!"); + } + + if (diskName == null || diskName.isEmpty()) { + return badRequestResponse("Disk name must not be empty!"); + } + + InitializeDiskTask initializeTask = new InitializeDiskTask(clusterService, clusterName, diskName, serverName); + try { + initializeTask.start(); + taskResource.addTask(initializeTask); + return acceptedResponse(RESTConstants.RESOURCE_PATH_CLUSTERS + "/" + clusterName + "/" + RESOURCE_TASKS + + "/" + initializeTask.getId()); + } catch (ConnectionException e) { + return errorResponse(e.getMessage()); + } + } + private void setGlusterUtil(GlusterUtil glusterUtil) { this.glusterUtil = glusterUtil; } diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/TasksResource.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/TasksResource.java index 4bf1c0cf..53122f11 100644 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/TasksResource.java +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/TasksResource.java @@ -20,9 +20,9 @@ */ package com.gluster.storage.management.server.resources; +import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_OPERATION; import static com.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_CLUSTER_NAME; import static com.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_TASK_ID; -import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_OPERATION; import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_PATH_CLUSTERS; import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_TASKS; @@ -40,26 +40,25 @@ import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; import com.gluster.storage.management.core.constants.RESTConstants; import com.gluster.storage.management.core.exceptions.GlusterRuntimeException; -import com.gluster.storage.management.core.model.Status; -import com.gluster.storage.management.core.model.Task; +import com.gluster.storage.management.core.exceptions.GlusterValidationException; import com.gluster.storage.management.core.model.TaskInfo; -import com.gluster.storage.management.core.response.TaskListResponse; -import com.gluster.storage.management.core.response.TaskResponse; +import com.gluster.storage.management.core.response.TaskInfoListResponse; +import com.gluster.storage.management.server.tasks.Task; import com.sun.jersey.spi.resource.Singleton; @Path(RESOURCE_PATH_CLUSTERS + "/{" + PATH_PARAM_CLUSTER_NAME + "}/" + RESOURCE_TASKS) @Singleton -public class TasksResource { +public class TasksResource extends AbstractResource { private Map<String, Task> tasksMap = new HashMap<String, Task>(); public TasksResource() { } - - public void addTask(Task task) { // task should be one of MuigrateDiskTask, FormatDiskTask, etc + public void addTask(Task task) { tasksMap.put(task.getId(), task); } @@ -70,18 +69,11 @@ public class TasksResource { public List<TaskInfo> getAllTasksInfo() { List<TaskInfo> allTasksInfo = new ArrayList<TaskInfo>(); for (Map.Entry<String, Task> entry : tasksMap.entrySet()) { - allTasksInfo.add(entry.getValue().getTaskInfo()); + checkTaskStatus(entry.getKey()); + allTasksInfo.add(entry.getValue().getTaskInfo()); // TaskInfo with latest status } return allTasksInfo; } - - public List<Task> getAllTasks() { - List<Task> allTasks = new ArrayList<Task>(); - for (Map.Entry<String, Task> entry : tasksMap.entrySet()) { - allTasks.add(entry.getValue()); - } - return allTasks; - } public Task getTask(String taskId) { for (Map.Entry<String, Task> entry : tasksMap.entrySet()) { @@ -91,63 +83,93 @@ public class TasksResource { } return null; } - + @GET @Produces(MediaType.APPLICATION_XML) - public TaskListResponse getTasks() { - TaskListResponse taskListResponse = new TaskListResponse(); + public Response getTasks() { + try { + return okResponse(new TaskInfoListResponse(getAllTasksInfo()), MediaType.APPLICATION_XML); + } catch (GlusterRuntimeException e) { + return errorResponse(e.getMessage()); + } + } + + @GET + @Path("/{" + PATH_PARAM_TASK_ID + "}") + @Produces(MediaType.APPLICATION_XML) + public Response getTaskStatus( @PathParam(PATH_PARAM_TASK_ID) String taskId) { try { - taskListResponse.setData(getAllTasksInfo()); - taskListResponse.setStatus(new Status(Status.STATUS_CODE_SUCCESS, "")); + Task task = checkTaskStatus(taskId); + return okResponse(task.getTaskInfo(), MediaType.APPLICATION_XML); } catch (GlusterRuntimeException e) { - taskListResponse.setStatus(new Status(e)); + return errorResponse(e.getMessage()); } - return taskListResponse; + } + + private Task checkTaskStatus(String taskId) { + Task task = getTask(taskId); + task.getTaskInfo().setStatus(task.checkStatus()); + return task; } @PUT @Path("/{" + PATH_PARAM_TASK_ID + "}") @Produces(MediaType.APPLICATION_XML) - public TaskResponse performTask(@PathParam(PATH_PARAM_TASK_ID) String taskId, - @FormParam(FORM_PARAM_OPERATION) String taskOperation) { + public Response performTask(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName, + @PathParam(PATH_PARAM_TASK_ID) String taskId, @FormParam(FORM_PARAM_OPERATION) String taskOperation) { Task task = getTask(taskId); - TaskInfo taskInfo = null; - TaskResponse taskResponse = new TaskResponse(); - + try { if (taskOperation.equals(RESTConstants.TASK_RESUME)) { - taskInfo = task.resume(); - } - if (taskOperation.equals(RESTConstants.TASK_PAUSE)) { - taskInfo = task.pause(); + task.resume(); + } else if (taskOperation.equals(RESTConstants.TASK_PAUSE)) { + task.pause(); + } else if (taskOperation.equals(RESTConstants.TASK_STOP)) { + task.stop(); + } else if (taskOperation.equals(RESTConstants.TASK_COMMIT)) { + task.commit(); } - if (taskOperation.equals(RESTConstants.TASK_STOP)) { - taskInfo = task.stop(); - } - taskResponse.setData(taskInfo); - taskResponse.setStatus(new Status(Status.STATUS_CODE_SUCCESS, "")); + return (Response) noContentResponse(); + } catch(GlusterValidationException ve) { + return badRequestResponse(ve.getMessage()); } catch (GlusterRuntimeException e) { - taskResponse.setStatus(new Status(e)); + return errorResponse(e.getMessage()); } - return taskResponse; } @DELETE @Path("/{" + PATH_PARAM_TASK_ID + "}") @Produces(MediaType.APPLICATION_XML) - public TaskResponse deleteTask(@PathParam(PATH_PARAM_TASK_ID) String taskId, + public Response deleteTask(@PathParam(PATH_PARAM_TASK_ID) String taskId, @QueryParam(FORM_PARAM_OPERATION) String taskOperation) { - TaskResponse taskResponse = new TaskResponse(); Task task = getTask(taskId); if (task == null) { - taskResponse.setStatus( new Status(Status.STATUS_CODE_FAILURE, "No such task " + taskId + "is found ")); + return notFoundResponse("Task [" + taskId + "] not found!"); } - if (taskOperation.equals("delete")) { - removeTask(task); - taskResponse.setStatus(new Status(Status.STATUS_CODE_SUCCESS, "Task [" + taskId - + "] removed successfully")); - } - return null; - } + + if(taskOperation == null || taskOperation.isEmpty()) { + return badRequestResponse("Parameter [" + FORM_PARAM_OPERATION + "] is missing in request!"); + } + + if(!taskOperation.equals(RESTConstants.TASK_STOP) && !taskOperation.equals(RESTConstants.TASK_DELETE)) { + return badRequestResponse("Invalid value [" + taskOperation + "] for parameter [" + FORM_PARAM_OPERATION + + "]"); + } + + try { + if (taskOperation.equals(RESTConstants.TASK_STOP)) { + task.stop(); + // On successfully stopping the task, we can delete (forget) it as it is no more useful + taskOperation = RESTConstants.TASK_DELETE; + } + if (taskOperation.equals(RESTConstants.TASK_DELETE)) { + removeTask(task); + } + + return noContentResponse(); + } catch (Exception e) { + return errorResponse(e.getMessage()); + } + } } diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/UsersResource.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/UsersResource.java index 0326793b..0ccb4263 100644 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/UsersResource.java +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/UsersResource.java @@ -18,6 +18,9 @@ *******************************************************************************/ package com.gluster.storage.management.server.resources; +import static com.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_USER; +import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_PATH_USERS; + import javax.ws.rs.FormParam; import javax.ws.rs.GET; import javax.ws.rs.PUT; @@ -25,68 +28,60 @@ import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.encoding.PasswordEncoder; -import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.provisioning.JdbcUserDetailsManager; import org.springframework.stereotype.Component; -import com.gluster.storage.management.core.model.Status; import com.sun.jersey.spi.resource.Singleton; @Singleton @Component -@Path("/users") -public class UsersResource { +@Path(RESOURCE_PATH_USERS) +public class UsersResource extends AbstractResource { @Autowired private JdbcUserDetailsManager jdbcUserService; @Autowired private PasswordEncoder passwordEncoder; - /** - * Authenticates given user with given password for login on current system - * - * @param user - * @param password - * @return true is user can be successfully authenticated using given password, else false - */ - /* - * NOTE: This method is no more required as user authentication is performed on every request by the spring security - * framework. Can be removed after testing. - */ - /* - * private boolean authenticate(String user, String password) { String tmpFileName = "tmp"; File saltFile = new - * File(tmpFileName); ProcessResult result = new ProcessUtil().executeCommand("get-user-password.py", user, - * tmpFileName); if (result.isSuccess()) { String salt = new FileUtil().readFileAsString(saltFile); String - * encryptedPassword = MD5Crypt.crypt(password, salt); return encryptedPassword.equals(salt); } - * - * return false; } - */ - - @Path("{user}") + @Path("{" + PATH_PARAM_USER + "}") @GET @Produces(MediaType.APPLICATION_XML) - public Status authenticate(@PathParam("user") String user) { + public Response authenticateXML(@PathParam("user") String user) { + // success only if the user passed in query is same as the one passed in security header + // spring security would have already authenticated the user credentials + return getAuthenticationResponse(user, MediaType.APPLICATION_XML); + } + + @Path("{" + PATH_PARAM_USER + "}") + @GET + @Produces(MediaType.APPLICATION_JSON) + public Response authenticateJSON(@PathParam("user") String user) { // success only if the user passed in query is same as the one passed in security header // spring security would have already authenticated the user credentials - return (SecurityContextHolder.getContext().getAuthentication().getName().equals(user) ? Status.STATUS_SUCCESS - : Status.STATUS_FAILURE); + return getAuthenticationResponse(user, MediaType.APPLICATION_JSON); } - @Path("{user}") + public Response getAuthenticationResponse(String user, String mediaType) { + return (SecurityContextHolder.getContext().getAuthentication().getName().equals(user) ? okResponse(mediaType) + : unauthorizedResponse()); + } + + @Path("{" + PATH_PARAM_USER + "}") @PUT - @Produces(MediaType.APPLICATION_XML) - public Status changePassword(@FormParam("oldpassword") String oldPassword, + public Response changePassword(@FormParam("oldpassword") String oldPassword, @FormParam("newpassword") String newPassword) { try { jdbcUserService.changePassword(oldPassword, passwordEncoder.encodePassword(newPassword, null)); - } catch (AuthenticationException ex) { + } catch (Exception ex) { + // TODO: Log the exception ex.printStackTrace(); - return new Status(Status.STATUS_CODE_FAILURE, "Could not change password: [" + ex.getMessage() + "]"); + return errorResponse("Could not change password. Error: [" + ex.getMessage() + "]"); } - return Status.STATUS_SUCCESS; + return noContentResponse(); } } 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 5d1f38e9..c9ae0fe5 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 @@ -23,8 +23,12 @@ package com.gluster.storage.management.server.resources; import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_ACCESS_PROTOCOLS; import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_AUTO_COMMIT; import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_BRICKS; -import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_CLUSTER_NAME; +import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_FIX_LAYOUT; +import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_FORCED_DATA_MIGRATE; +import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_MIGRATE_DATA; import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_OPERATION; +import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_OPTION_KEY; +import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_OPTION_VALUE; import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_REPLICA_COUNT; import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_SOURCE; import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_STRIPE_COUNT; @@ -33,7 +37,6 @@ import static com.gluster.storage.management.core.constants.RESTConstants.FORM_P import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_VOLUME_NAME; import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_VOLUME_OPTIONS; import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_VOLUME_TYPE; -import static com.gluster.storage.management.core.constants.RESTConstants.*; import static com.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_CLUSTER_NAME; import static com.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_VOLUME_NAME; import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_BRICKS; @@ -44,13 +47,13 @@ import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_ import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_LINE_COUNT; import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_LOG_SEVERITY; import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_TO_TIMESTAMP; -import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_VOLUME_NAME; import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_BRICKS; import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_DEFAULT_OPTIONS; import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_DOWNLOAD; import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_LOGS; import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_OPTIONS; import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_PATH_CLUSTERS; +import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_TASKS; 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; @@ -91,16 +94,16 @@ import com.gluster.storage.management.core.model.Volume.VOLUME_TYPE; import com.gluster.storage.management.core.model.VolumeLogMessage; import com.gluster.storage.management.core.response.GenericResponse; import com.gluster.storage.management.core.response.LogMessageListResponse; -import com.gluster.storage.management.core.response.TaskResponse; import com.gluster.storage.management.core.response.VolumeListResponse; import com.gluster.storage.management.core.response.VolumeOptionInfoListResponse; import com.gluster.storage.management.core.utils.DateUtil; import com.gluster.storage.management.core.utils.FileUtil; -import com.gluster.storage.management.core.utils.GlusterCoreUtil; import com.gluster.storage.management.core.utils.ProcessUtil; import com.gluster.storage.management.server.constants.VolumeOptionsDefaults; import com.gluster.storage.management.server.data.ClusterInfo; import com.gluster.storage.management.server.services.ClusterService; +import com.gluster.storage.management.server.tasks.MigrateDiskTask; +import com.gluster.storage.management.server.tasks.RebalanceVolumeTask; import com.gluster.storage.management.server.utils.GlusterUtil; import com.gluster.storage.management.server.utils.ServerUtil; import com.sun.jersey.api.core.InjectParam; @@ -109,14 +112,10 @@ import com.sun.jersey.spi.resource.Singleton; @Singleton @Path(RESOURCE_PATH_CLUSTERS + "/{" + PATH_PARAM_CLUSTER_NAME + "}/" + RESOURCE_VOLUMES) public class VolumesResource extends AbstractResource { - private static final String PREPARE_BRICK_SCRIPT = "create_volume_directory.py"; private static final String VOLUME_DIRECTORY_CLEANUP_SCRIPT = "clear_volume_directory.py"; private static final String VOLUME_BRICK_LOG_SCRIPT = "get_volume_brick_log.py"; @InjectParam - private GlusterServersResource glusterServersResource; - - @InjectParam private ServerUtil serverUtil; @InjectParam @@ -128,6 +127,9 @@ public class VolumesResource extends AbstractResource { @InjectParam private VolumeOptionsDefaults volumeOptionsDefaults; + @InjectParam + private TasksResource taskResource; + @GET @Produces({MediaType.APPLICATION_XML}) public Response getVolumesXML(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName) { @@ -145,15 +147,21 @@ public class VolumesResource extends AbstractResource { return badRequestResponse("Cluster name must not be empty!"); } - if (clusterService.getCluster(clusterName) == null) { - return badRequestResponse("Cluster [" + clusterName + "] not found!"); + ClusterInfo cluster = clusterService.getCluster(clusterName); + if (cluster == null) { + return notFoundResponse("Cluster [" + clusterName + "] not found!"); + } + + if(cluster.getServers().size() == 0) { + // no server added yet. return an empty array. + return okResponse(new VolumeListResponse(), mediaType); } return okResponse(getVolumes(clusterName), mediaType); } public VolumeListResponse getVolumes(String clusterName) { - GlusterServer onlineServer = glusterServersResource.getOnlineServer(clusterName); + GlusterServer onlineServer = clusterService.getOnlineServer(clusterName); if (onlineServer == null) { return new VolumeListResponse(new ArrayList<Volume>()); } @@ -162,7 +170,7 @@ public class VolumesResource extends AbstractResource { return new VolumeListResponse(glusterUtil.getAllVolumes(onlineServer.getName())); } catch (ConnectionException e) { // online server has gone offline! try with a different one. - onlineServer = glusterServersResource.getNewOnlineServer(clusterName); + onlineServer = clusterService.getNewOnlineServer(clusterName); if (onlineServer == null) { return new VolumeListResponse(new ArrayList<Volume>()); } @@ -188,7 +196,7 @@ public class VolumesResource extends AbstractResource { } 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) { @@ -199,7 +207,7 @@ public class VolumesResource extends AbstractResource { return badRequestResponse("Stripe count must be a positive integer"); } - GlusterServer onlineServer = glusterServersResource.getOnlineServer(clusterName); + GlusterServer onlineServer = clusterService.getOnlineServer(clusterName); if (onlineServer == null) { return errorResponse("No online servers found in cluster [" + clusterName + "]"); } @@ -209,7 +217,7 @@ public class VolumesResource extends AbstractResource { return createdResponse(volumeName); } catch (ConnectionException e) { // online server has gone offline! try with a different one. - onlineServer = glusterServersResource.getNewOnlineServer(clusterName); + onlineServer = clusterService.getNewOnlineServer(clusterName); if (onlineServer == null) { return errorResponse("No online servers found in cluster [" + clusterName + "]"); } @@ -274,7 +282,7 @@ public class VolumesResource extends AbstractResource { } if (clusterService.getCluster(clusterName) == null) { - return badRequestResponse("Cluster [" + clusterName + "] not found!"); + return notFoundResponse("Cluster [" + clusterName + "] not found!"); } try { @@ -287,7 +295,7 @@ public class VolumesResource extends AbstractResource { private Volume getVolume(String clusterName, String volumeName) { Volume volume; - GlusterServer onlineServer = glusterServersResource.getOnlineServer(clusterName); + GlusterServer onlineServer = clusterService.getOnlineServer(clusterName); if (onlineServer == null) { throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]"); } @@ -296,7 +304,7 @@ public class VolumesResource extends AbstractResource { volume = glusterUtil.getVolume(volumeName, onlineServer.getName()); } catch (ConnectionException e) { // online server has gone offline! try with a different one. - onlineServer = glusterServersResource.getNewOnlineServer(clusterName); + onlineServer = clusterService.getNewOnlineServer(clusterName); if (onlineServer == null) { throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]"); } @@ -309,7 +317,10 @@ 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!"); } @@ -319,31 +330,38 @@ public class VolumesResource extends AbstractResource { } 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 + "]"); + try { + if (operation.equals(RESTConstants.TASK_REBALANCE_START)) { + String taskId = rebalanceStart(clusterName, volumeName, isFixLayout, isMigrateData, isForcedDataMigrate); + return acceptedResponse(RESTConstants.RESOURCE_PATH_CLUSTERS + "/" + clusterName + "/" + RESOURCE_TASKS + + "/" + taskId); + } else if (operation.equals(RESTConstants.TASK_REBALANCE_STOP)) { + rebalanceStop(clusterName, volumeName); + } else { + performVolumeOperation(clusterName, volumeName, operation); + } + return noContentResponse(); + } catch(Exception e) { + return errorResponse(e.getMessage()); } - + } + + private void performVolumeOperation(String clusterName, String volumeName, String operation) { + GlusterServer onlineServer = clusterService.getOnlineServer(clusterName); try { - performOperation(volumeName, operation, onlineServer); - } catch (ConnectionException e) { - // online server has gone offline! try with a different one. - onlineServer = glusterServersResource.getNewOnlineServer(clusterName); if (onlineServer == null) { - return errorResponse("No online servers found in cluster [" + clusterName + "]"); - } - - try { - performOperation(volumeName, operation, onlineServer); - } catch(Exception e1) { - // TODO: Log the exception - return errorResponse(e1.getMessage()); + throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]"); } + + performOperation(volumeName, operation, onlineServer); + } catch (ConnectionException e) { + // online server has gone offline! try with a different one. + onlineServer = clusterService.getNewOnlineServer(clusterName); + performOperation(volumeName, operation, onlineServer); } - return noContentResponse(); } private Status performOperation(String volumeName, String operation, GlusterServer onlineServer) { @@ -370,7 +388,7 @@ public class VolumesResource extends AbstractResource { } if (clusterService.getCluster(clusterName) == null) { - return badRequestResponse("Cluster [" + clusterName + "] not found!"); + return notFoundResponse("Cluster [" + clusterName + "] not found!"); } if (deleteFlag == null) { @@ -386,7 +404,7 @@ public class VolumesResource extends AbstractResource { } List<Brick> bricks = volume.getBricks(); - Status status = glusterUtil.deleteVolume(volumeName, glusterServersResource.getOnlineServer(clusterName) + Status status = glusterUtil.deleteVolume(volumeName, clusterService.getOnlineServer(clusterName) .getName()); if(!status.isSuccess()) { return errorResponse("Couldn't delete volume [" + volumeName + "]. Error: " + status); @@ -423,14 +441,14 @@ public class VolumesResource extends AbstractResource { } if (clusterService.getCluster(clusterName) == null) { - return badRequestResponse("Cluster [" + clusterName + "] not found!"); + return notFoundResponse("Cluster [" + clusterName + "] not found!"); } if(deleteFlag == null) { deleteFlag = false; } - GlusterServer onlineServer = glusterServersResource.getOnlineServer(clusterName); + GlusterServer onlineServer = clusterService.getOnlineServer(clusterName); if (onlineServer == null) { return errorResponse("No online servers found in cluster [" + clusterName + "]"); } @@ -456,7 +474,7 @@ public class VolumesResource extends AbstractResource { glusterUtil.removeBricks(volumeName, brickList, onlineServer.getName()); } catch (ConnectionException e) { // online server has gone offline! try with a different one. - onlineServer = glusterServersResource.getNewOnlineServer(clusterName); + onlineServer = clusterService.getNewOnlineServer(clusterName); if (onlineServer == null) { throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]"); } @@ -530,10 +548,10 @@ public class VolumesResource extends AbstractResource { } if (clusterService.getCluster(clusterName) == null) { - return badRequestResponse("Cluster [" + clusterName + "] not found!"); + return notFoundResponse("Cluster [" + clusterName + "] not found!"); } - GlusterServer onlineServer = glusterServersResource.getOnlineServer(clusterName); + GlusterServer onlineServer = clusterService.getOnlineServer(clusterName); if (onlineServer == null) { return errorResponse("No online servers found in cluster [" + clusterName + "]"); } @@ -542,7 +560,7 @@ public class VolumesResource extends AbstractResource { glusterUtil.setOption(volumeName, key, value, onlineServer.getName()); } catch (ConnectionException e) { // online server has gone offline! try with a different one. - onlineServer = glusterServersResource.getNewOnlineServer(clusterName); + onlineServer = clusterService.getNewOnlineServer(clusterName); if (onlineServer == null) { return errorResponse("No online servers found in cluster [" + clusterName + "]"); } @@ -572,10 +590,10 @@ public class VolumesResource extends AbstractResource { } if (clusterService.getCluster(clusterName) == null) { - return badRequestResponse("Cluster [" + clusterName + "] not found!"); + return notFoundResponse("Cluster [" + clusterName + "] not found!"); } - GlusterServer onlineServer = glusterServersResource.getOnlineServer(clusterName); + GlusterServer onlineServer = clusterService.getOnlineServer(clusterName); if (onlineServer == null) { return errorResponse("No online servers found in cluster [" + clusterName + "]"); } @@ -584,7 +602,7 @@ public class VolumesResource extends AbstractResource { glusterUtil.resetOptions(volumeName, onlineServer.getName()); } catch (ConnectionException e) { // online server has gone offline! try with a different one. - onlineServer = glusterServersResource.getNewOnlineServer(clusterName); + onlineServer = clusterService.getNewOnlineServer(clusterName); if (onlineServer == null) { return errorResponse("No online servers found in cluster [" + clusterName + "]"); } @@ -628,27 +646,20 @@ public class VolumesResource extends AbstractResource { // Usage: get_volume_disk_log.py <volumeName> <diskName> <lineCount> Object responseObj = serverUtil.executeOnServer(true, brick.getServerName(), VOLUME_BRICK_LOG_SCRIPT + " " + logFilePath + " " + lineCount, LogMessageListResponse.class); - Status status = null; + LogMessageListResponse response = null; if (responseObj instanceof LogMessageListResponse) { response = (LogMessageListResponse) responseObj; - status = response.getStatus(); + // populate disk and trim other fields + List<VolumeLogMessage> logMessages = response.getLogMessages(); + for (VolumeLogMessage logMessage : logMessages) { + logMessage.setBrickDirectory(brick.getBrickDirectory()); + } + return logMessages; } else { - status = (Status) responseObj; - } - - if (!status.isSuccess()) { + Status status = (Status) responseObj; throw new GlusterRuntimeException(status.toString()); } - - // populate disk and trim other fields - List<VolumeLogMessage> logMessages = response.getLogMessages(); - for (VolumeLogMessage logMessage : logMessages) { - logMessage.setBrickDirectory(brick.getBrickDirectory()); - logMessage.setMessage(logMessage.getMessage().trim()); - logMessage.setSeverity(logMessage.getSeverity().trim()); - } - return logMessages; } @GET @@ -665,7 +676,7 @@ public class VolumesResource extends AbstractResource { } if (clusterService.getCluster(clusterName) == null) { - return badRequestResponse("Cluster [" + clusterName + "] not found!"); + return notFoundResponse("Cluster [" + clusterName + "] not found!"); } try { @@ -757,7 +768,7 @@ public class VolumesResource extends AbstractResource { } if (clusterService.getCluster(clusterName) == null) { - return badRequestResponse("Cluster [" + clusterName + "] not found!"); + return notFoundResponse("Cluster [" + clusterName + "] not found!"); } List<VolumeLogMessage> logMessages = null; @@ -862,10 +873,10 @@ public class VolumesResource extends AbstractResource { } if (clusterService.getCluster(clusterName) == null) { - return badRequestResponse("Cluster [" + clusterName + "] not found!"); + return notFoundResponse("Cluster [" + clusterName + "] not found!"); } - GlusterServer onlineServer = glusterServersResource.getOnlineServer(clusterName); + GlusterServer onlineServer = clusterService.getOnlineServer(clusterName); if (onlineServer == null) { return errorResponse("No online servers found in cluster [" + clusterName + "]"); } @@ -875,7 +886,7 @@ public class VolumesResource extends AbstractResource { glusterUtil.addBricks(volumeName, brickList, onlineServer.getName()); } catch (ConnectionException e) { // online server has gone offline! try with a different one. - onlineServer = glusterServersResource.getNewOnlineServer(clusterName); + onlineServer = clusterService.getNewOnlineServer(clusterName); if (onlineServer == null) { return errorResponse("No online servers found in cluster [" + clusterName + "]"); } @@ -915,10 +926,10 @@ public class VolumesResource extends AbstractResource { } if (clusterService.getCluster(clusterName) == null) { - return badRequestResponse("Cluster [" + clusterName + "] not found!"); + return notFoundResponse("Cluster [" + clusterName + "] not found!"); } - GlusterServer onlineServer = glusterServersResource.getOnlineServer(clusterName); + GlusterServer onlineServer = clusterService.getOnlineServer(clusterName); if (onlineServer == null) { return errorResponse("No online servers found in cluster [" + clusterName + "]"); } @@ -929,23 +940,54 @@ public class VolumesResource extends AbstractResource { String taskId = null; try { - taskId = glusterUtil.migrateBrickStart(volumeName, fromBrick, toBrick, autoCommit, onlineServer.getName()); - } catch (ConnectionException e) { - // online server has gone offline! try with a different one. - onlineServer = glusterServersResource.getNewOnlineServer(clusterName); - - try { - taskId = glusterUtil.migrateBrickStart(volumeName, fromBrick, toBrick, autoCommit, onlineServer.getName()); - } catch(Exception e1) { - return errorResponse(e1.getMessage()); - } - } catch(Exception e1) { - return errorResponse(e1.getMessage()); + taskId = migrateBrickStart(clusterName, volumeName, fromBrick, toBrick, autoCommit); + }catch(Exception e) { + return errorResponse(e.getMessage()); } - return acceptedResponse(RESTConstants.RESOURCE_PATH_CLUSTERS, clusterName, RESOURCE_TASKS, taskId); + return acceptedResponse(RESTConstants.RESOURCE_PATH_CLUSTERS + "/" + clusterName + "/" + RESOURCE_TASKS + "/" + + taskId); } - + + private String migrateBrickStart(String clusterName, String volumeName, String fromBrick, String toBrick, + Boolean autoCommit) { + MigrateDiskTask migrateDiskTask = new MigrateDiskTask(clusterService, clusterName, volumeName, fromBrick, + toBrick); + migrateDiskTask.setAutoCommit(autoCommit); + migrateDiskTask.start(); + taskResource.addTask(migrateDiskTask); + return migrateDiskTask.getTaskInfo().getName(); // Return Task ID + } + + private String rebalanceStart(String clusterName, String volumeName, Boolean isFixLayout, Boolean isMigrateData, + Boolean isForcedDataMigrate) { + String layout = ""; + if (isForcedDataMigrate) { + layout = "forced-data-migrate"; + } else if (isMigrateData) { + layout = "migrate-data"; + } else if (isFixLayout) { + layout = "fix-layout"; + } + + return rebalanceStart(clusterName, volumeName, layout); + } + + public String rebalanceStart(String clusterName, String volumeName, String layout) { + RebalanceVolumeTask rebalanceTask = new RebalanceVolumeTask(clusterService, clusterName, volumeName); + rebalanceTask.setLayout(layout); + rebalanceTask.start(); + taskResource.addTask(rebalanceTask); + return rebalanceTask.getId(); + } + + public void rebalanceStop(String clusterName, String volumeName) { + // TODO: arrive at the task id and fetch it + String taskId = ""; + + taskResource.getTask(taskId).stop(); + } + public static void main(String[] args) throws ClassNotFoundException { VolumesResource vr = new VolumesResource(); // VolumeListResponse response = vr.getAllVolumes(); @@ -969,6 +1011,10 @@ public class VolumesResource extends AbstractResource { // System.out.println("Code : " + status.getCode()); // System.out.println("Message " + status.getMessage()); - vr.removeBricks("testCluster", "test", "192.168.1.210:sdb", true); + // vr.removeBricks("testCluster", "test", "192.168.1.210:sdb", true); + + String taskId = vr.migrateBrickStart("myGluster", "students", "devserver1:/export/sdc/students", + "devserver2:/export/sdb/students", true); + } } diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/services/ClusterService.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/services/ClusterService.java index 0aabb714..b622c3a1 100644 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/services/ClusterService.java +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/services/ClusterService.java @@ -33,15 +33,17 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.gluster.storage.management.core.constants.CoreConstants; +import com.gluster.storage.management.core.exceptions.ConnectionException; import com.gluster.storage.management.core.exceptions.GlusterRuntimeException; import com.gluster.storage.management.core.model.GlusterServer; -import com.gluster.storage.management.core.model.Status; +import com.gluster.storage.management.core.model.GlusterServer.SERVER_STATUS; +import com.gluster.storage.management.core.utils.LRUCache; import com.gluster.storage.management.server.data.ClusterInfo; import com.gluster.storage.management.server.data.PersistenceDao; import com.gluster.storage.management.server.data.ServerInfo; import com.gluster.storage.management.server.utils.GlusterUtil; +import com.gluster.storage.management.server.utils.ServerUtil; import com.gluster.storage.management.server.utils.SshUtil; -import com.sun.jersey.api.core.InjectParam; /** * Service class for functionality related to clusters @@ -60,12 +62,70 @@ public class ClusterService { @Autowired private SshUtil sshUtil; + @Autowired + private ServerUtil serverUtil; + + private LRUCache<String, GlusterServer> onlineServerCache = new LRUCache<String, GlusterServer>(3); + + public void addOnlineServer(String clusterName, GlusterServer server) { + onlineServerCache.put(clusterName, server); + } + + public void removeOnlineServer(String clusterName) { + onlineServerCache.remove(clusterName); + } + + // uses cache + public GlusterServer getOnlineServer(String clusterName, String exceptServerName) { + GlusterServer server = onlineServerCache.get(clusterName); + if (server != null && !server.getName().equals(exceptServerName)) { + return server; + } + + return getNewOnlineServer(clusterName, exceptServerName); + } + + public GlusterServer getNewOnlineServer(String clusterName) { + return getNewOnlineServer(clusterName, ""); + } + + public GlusterServer getOnlineServer(String clusterName) { + return getOnlineServer(clusterName, ""); + } + + // Doesn't use cache + public GlusterServer getNewOnlineServer(String clusterName, String exceptServerName) { + ClusterInfo cluster = getCluster(clusterName); + if (cluster == null) { + throw new GlusterRuntimeException("Cluster [" + clusterName + "] is not found!"); + } + + for (ServerInfo serverInfo : cluster.getServers()) { + GlusterServer server = new GlusterServer(serverInfo.getName()); + server.setStatus(SERVER_STATUS.ONLINE); + try { + serverUtil.fetchServerDetails(server); + if (server.isOnline() && !server.getName().equals(exceptServerName)) { + // server is online. add it to cache and return + addOnlineServer(clusterName, server); + return server; + } + } catch(ConnectionException e) { + // server is offline. continue checking next one. + continue; + } + } + + // no online server found. + throw new GlusterRuntimeException("No online server found in cluster [" + clusterName + "]"); + } + public List<ClusterInfo> getAllClusters() { return clusterDao.findAll(); } public ClusterInfo getCluster(String clusterName) { - List<ClusterInfo> clusters = clusterDao.findBy("name = ?1", clusterName); + List<ClusterInfo> clusters = clusterDao.findBy("UPPER(name) = ?1", clusterName.toUpperCase()); if(clusters.size() == 0) { return null; } @@ -74,7 +134,7 @@ public class ClusterService { } public ClusterInfo getClusterForServer(String serverName) { - List<ServerInfo> servers = serverDao.findBy("name = ?1", serverName); + List<ServerInfo> servers = serverDao.findBy("UPPER(name) = ?1", serverName.toUpperCase()); if(servers.size() == 0) { return null; } diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/tasks/InitializeDiskTask.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/tasks/InitializeDiskTask.java new file mode 100644 index 00000000..5f3f8e30 --- /dev/null +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/tasks/InitializeDiskTask.java @@ -0,0 +1,114 @@ +/** + * 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 com.gluster.storage.management.server.tasks; + +import com.gluster.storage.management.core.model.Status; +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.server.services.ClusterService; +import com.gluster.storage.management.server.utils.SshUtil; + +public class InitializeDiskTask extends Task { + + private static final String INITIALIZE_DISK_SCRIPT = "initialize_disk.py"; + private static final String INITIALIZE_DISK_STATUS_SCRIPT = "initialize_disk_status.py"; + + private String serverName; + private String diskName; + private SshUtil sshUtil = new SshUtil(); + + public InitializeDiskTask(ClusterService clusterService, String clusterName, String serverName, String diskName) { + super(clusterService, clusterName, TASK_TYPE.DISK_FORMAT, diskName, "Initialize disk " + serverName + ":" + + diskName, false, false, false); + + setServerName(serverName); + setDiskName(diskName); + } + + public InitializeDiskTask(ClusterService clusterService, String clusterName, TaskInfo info) { + super(clusterService, clusterName, info); + } + + @Override + public String getId() { + return taskInfo.getType() + "-" + serverName + ":" + diskName; + } + + @Override + public void resume() { + getTaskInfo().setStatus( new TaskStatus( new Status(Status.STATUS_CODE_FAILURE, "Can not resume disk initialization"))); + } + + @Override + public void stop() { + getTaskInfo().setStatus( new TaskStatus( new Status(Status.STATUS_CODE_FAILURE, "Can not stop disk initialization"))); + } + + @Override + public void pause() { + getTaskInfo().setStatus( new TaskStatus( new Status(Status.STATUS_CODE_FAILURE, "Can not suspend disk initialization"))); + } + + @Override + public void commit() { + // TODO Auto-generated method stub + } + + @Override + public TASK_TYPE getType() { + return TASK_TYPE.DISK_FORMAT; + } + + @Override + public TaskInfo getTaskInfo() { + return getTaskInfo(); + } + + @Override + public void start() { + getTaskInfo().setStatus( + new TaskStatus(new Status(sshUtil.executeRemote(getServerName(), INITIALIZE_DISK_SCRIPT + " " + + getDiskName())))); + } + + @Override + public TaskStatus checkStatus() { + return new TaskStatus(new Status(sshUtil.executeRemote(getServerName(), INITIALIZE_DISK_STATUS_SCRIPT + " " + + getDiskName()))); + } + + 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; + } +} diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/tasks/MigrateDiskTask.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/tasks/MigrateDiskTask.java index df637ab1..9bdc9c94 100644 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/tasks/MigrateDiskTask.java +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/tasks/MigrateDiskTask.java @@ -20,13 +20,16 @@ */ package com.gluster.storage.management.server.tasks; -import org.springframework.beans.factory.annotation.Autowired; - +import com.gluster.storage.management.core.exceptions.ConnectionException; +import com.gluster.storage.management.core.exceptions.GlusterRuntimeException; 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.services.ClusterService; import com.gluster.storage.management.server.utils.SshUtil; +import com.sun.jersey.core.util.Base64; public class MigrateDiskTask extends Task { @@ -60,67 +63,176 @@ public class MigrateDiskTask extends Task { this.autoCommit = autoCommit; } - public MigrateDiskTask(TASK_TYPE type, String volumeName, String fromBrick, String toBrick) { - super(type, volumeName); + public MigrateDiskTask(ClusterService clusterService, String clusterName, String volumeName, String fromBrick, String toBrick) { + super(clusterService, clusterName, TASK_TYPE.BRICK_MIGRATE, volumeName, "Brick Migration on volume [" + + volumeName + "] from [" + fromBrick + "] to [" + toBrick + "]", true, true, true); setFromBrick(fromBrick); setToBrick(toBrick); - setTaskDescription(); - getTaskInfo().setCanPause(true); - getTaskInfo().setCanStop(true); + taskInfo.setName(getId()); } - public MigrateDiskTask(TaskInfo info) { - super(info); - setTaskDescription(); + public MigrateDiskTask(ClusterService clusterService, String clusterName, TaskInfo info) { + super(clusterService, clusterName, info); } @Override public String getId() { - return getTaskInfo().getId(); + return new String( Base64.encode( taskInfo.getType() + "-" + taskInfo.getReference() + "-" + fromBrick + "-" + toBrick )); } @Override - public TaskInfo start() { - getTaskInfo().setStatus( - new TaskStatus(new Status(sshUtil.executeRemote(getOnlineServer(), "gluster volume replace-brick " - + getTaskInfo().getReference() + " " + getFromBrick() + " " + getToBrick() + " start" ) ))); - return getTaskInfo(); + public void start() { + try { + startMigration(getOnlineServer().getName()); + } catch(ConnectionException e) { + // online server might have gone offline. try with a new one. + startMigration(getNewOnlineServer().getName()); + } + } + + private void startMigration(String onlineServerName) { + String command = "gluster volume replace-brick " + getTaskInfo().getReference() + " " + getFromBrick() + " " + + getToBrick() + " start"; + ProcessResult processResult = sshUtil.executeRemote(onlineServerName, command); + if (processResult.isSuccess()) { + if (processResult.getOutput().trim().matches(".*started successfully$")) { + getTaskInfo().setStatus(new TaskStatus(new Status(Status.STATUS_CODE_RUNNING, processResult.getOutput().trim()))); + return; + } + } + + // if we come here, it means task couldn't be started successfully. + throw new GlusterRuntimeException(processResult.toString()); } @Override - public TaskInfo resume() { - return start(); + public void pause() { + try { + pauseMigration(getOnlineServer().getName()); + } catch(ConnectionException e) { + // online server might have gone offline. try with a new one. + pauseMigration(getNewOnlineServer().getName()); + } } + private void pauseMigration(String onlineServer) { + String command = "gluster volume replace-brick " + getTaskInfo().getReference() + " " + getFromBrick() + " " + getToBrick() + + " pause"; + + ProcessResult processResult = sshUtil.executeRemote(onlineServer, command); + TaskStatus taskStatus = new TaskStatus(); + if (processResult.isSuccess()) { + if (processResult.getOutput().matches("*pause")) { //TODO replace correct pattern to identify the pause status + taskStatus.setCode(Status.STATUS_CODE_PAUSE); + taskStatus.setMessage(processResult.getOutput()); + getTaskInfo().setStatus(taskStatus); + return; + } + } + + // if we reach here, it means rebalance start failed. + throw new GlusterRuntimeException(processResult.toString()); + } + + + @Override + public void resume() { + start(); + } + @Override - public TaskInfo stop() { - getTaskInfo().setStatus( - new TaskStatus(new Status(sshUtil.executeRemote(getOnlineServer(), "gluster volume replace-brick " - + getTaskInfo().getReference() + " " + getFromBrick() + " " + getToBrick() + " abort" ) ))); - return getTaskInfo(); + public void commit() { + try { + commitMigration(getOnlineServer().getName()); + } catch(ConnectionException e) { + // online server might have gone offline. try with a new one. + commitMigration(getNewOnlineServer().getName()); + } } @Override - public TaskInfo pause() { - getTaskInfo().setStatus( - new TaskStatus(new Status(sshUtil.executeRemote(getOnlineServer(), "gluster volume replace-brick " - + getTaskInfo().getReference() + " " + getFromBrick() + " " + getToBrick() + " pause" ) ))); - return getTaskInfo(); + public void stop() { + try { + stopMigration(getOnlineServer().getName()); + } catch(ConnectionException e) { + // online server might have gone offline. try with a new one. + stopMigration(getNewOnlineServer().getName()); + } + } + + private void stopMigration(String serverName) { + String command = "gluster volume replace-brick " + getTaskInfo().getReference() + " " + getFromBrick() + " " + getToBrick() + + " abort"; + + ProcessResult processResult = sshUtil.executeRemote(serverName, command); + TaskStatus taskStatus = new TaskStatus(); + if (processResult.isSuccess()) { + if (processResult.getOutput().trim().matches(".*aborted successfully$")) { + taskStatus.setCode(Status.STATUS_CODE_SUCCESS); + taskStatus.setMessage(processResult.getOutput()); + getTaskInfo().setStatus(taskStatus); + return; + } + } + // if we reach here, it means rebalance start failed. + throw new GlusterRuntimeException(processResult.toString()); } @Override - public void setTaskDescription() { - TaskInfo taskInfo = getTaskInfo(); - getTaskInfo().setDescription( - getTypeStr() + " on volume [" + taskInfo.getReference() + "] from [" + getFromBrick() - + "] to [" + getToBrick() + "]"); + public TaskStatus checkStatus() { + try { + return checkMigrationStatus(getOnlineServer().getName()); + } catch(ConnectionException e) { + // online server might have gone offline. try with a new one. + return checkMigrationStatus(getNewOnlineServer().getName()); + } } - - @Override - public TaskInfo status() { - return getTaskInfo(); + + public void commitMigration(String serverName) { + String command = "gluster volume replace-brick " + getTaskInfo().getReference() + " " + getFromBrick() + " " + + getToBrick() + " commit"; + + ProcessResult processResult = sshUtil.executeRemote(serverName, command); + TaskStatus taskStatus = new TaskStatus(); + if (processResult.isSuccess()) { + if (processResult.getOutput().trim().matches(".*commit successful$")) { + taskStatus.setCode(Status.STATUS_CODE_SUCCESS); + taskStatus.setMessage(processResult.getOutput()); // Common + getTaskInfo().setStatus(taskStatus); + return; + } + } + + // if we reach here, it means rebalance start failed. + throw new GlusterRuntimeException(processResult.toString()); + } + + + private TaskStatus checkMigrationStatus(String serverName) { + String command = "gluster volume replace-brick " + getTaskInfo().getReference() + " " + getFromBrick() + " " + + getToBrick() + " status"; + ProcessResult processResult = sshUtil.executeRemote(serverName, command); + TaskStatus taskStatus = new TaskStatus(); + if (processResult.isSuccess()) { + if (processResult.getOutput().trim().matches("^Number of files migrated.*Migration complete$")) { + taskStatus.setCode(Status.STATUS_CODE_COMMIT_PENDING); + if (autoCommit) { + commitMigration(serverName); + } + } else if ( processResult.getOutput().trim().matches("^Number of files migrated.*Current file=.*")) { + 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 + taskInfo.setStatus(taskStatus); // Update the task status + return taskStatus; } } 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..7f9fb6bf --- /dev/null +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/tasks/RebalanceVolumeTask.java @@ -0,0 +1,153 @@ +/** + * 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 com.gluster.storage.management.server.tasks; + +import com.gluster.storage.management.core.exceptions.ConnectionException; +import com.gluster.storage.management.core.exceptions.GlusterRuntimeException; +import com.gluster.storage.management.core.model.Status; +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.services.ClusterService; +import com.gluster.storage.management.server.utils.SshUtil; + +public class RebalanceVolumeTask extends Task { + + private String layout; + private SshUtil sshUtil = new SshUtil(); + + public RebalanceVolumeTask(ClusterService clusterService, String clusterName, TaskInfo taskInfo) { + super(clusterService, clusterName, taskInfo); + } + + public RebalanceVolumeTask(ClusterService clusterService, String clusterName, String volumeName) { + super(clusterService, clusterName, TASK_TYPE.VOLUME_REBALANCE, volumeName, "Volume rebalance running on " + volumeName, false, true, false); + } + + @Override + public String getId() { + return taskInfo.getType() + "-" + taskInfo.getReference(); + } + + @Override + public void start() { + try { + startRebalance(getOnlineServer().getName()); + } catch(ConnectionException e) { + // online server might have gone offline. try with a new one + startRebalance(getNewOnlineServer().getName()); + } + } + + private void startRebalance(String serverName) { + String command = "gluster volume rebalance " + getTaskInfo().getReference() + " " + getLayout() + " start"; + ProcessResult processResult = sshUtil.executeRemote(serverName, command); + if (processResult.isSuccess()) { + if (processResult.getOutput().trim().matches(".*has been successful$")) { + getTaskInfo().setStatus(new TaskStatus(new Status(Status.STATUS_CODE_RUNNING, processResult.getOutput()))); + } + } + + // if we reach here, it means rebalance start failed. + throw new GlusterRuntimeException(processResult.toString()); + } + + @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 { + stopRebalance(getOnlineServer().getName()); + } catch(ConnectionException e) { + // online server might have gone offline. try with a new one + stopRebalance(getNewOnlineServer().getName()); + } + } + + private void stopRebalance(String serverName) { + 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 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 checkRebalanceStatus(getOnlineServer().getName()); + } catch(ConnectionException e) { + // online server might have gone offline. try with a new one. + return checkRebalanceStatus(getNewOnlineServer().getName()); + } + } + + // TODO: This method should move to glusterUtil + private TaskStatus checkRebalanceStatus(String serverName) { + String command = "gluster volume rebalance " + getTaskInfo().getReference() + " status"; + ProcessResult processResult = sshUtil.executeRemote(serverName, command); + TaskStatus taskStatus = new TaskStatus(); + if (processResult.isSuccess()) { + if (processResult.getOutput().trim().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) { + this.layout = layout; + } + + public String getLayout() { + 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/tasks/Task.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/tasks/Task.java new file mode 100644 index 00000000..49cd0b8b --- /dev/null +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/tasks/Task.java @@ -0,0 +1,111 @@ +/** + * 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 com.gluster.storage.management.server.tasks; + +import com.gluster.storage.management.core.model.GlusterServer; +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.server.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.setCanPause(canPause); + taskInfo.setCanStop(canStop); + taskInfo.setCanCommit(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(); +} 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..788e3eab 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,6 @@ 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.Task.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; @@ -47,6 +46,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 @@ -536,21 +536,6 @@ public class GlusterUtil { return logFileName; } - - public String migrateBrickStart(String volumeName, String fromBrick, String toBrick, Boolean autoCommit, - String knownServer) { - MigrateDiskTask migrateDiskTask = new MigrateDiskTask(TASK_TYPE.BRICK_MIGRATE, volumeName, fromBrick, toBrick); - migrateDiskTask.setOnlineServer(knownServer); - migrateDiskTask.setAutoCommit(autoCommit); - - TaskInfo taskInfo = migrateDiskTask.start(); - if (taskInfo.isSuccess()) { - taskResource.addTask(migrateDiskTask); - } - - return taskInfo.getId(); - } - public Status removeBricks(String volumeName, List<String> bricks, String knownServer) { StringBuilder command = new StringBuilder("gluster --mode=script volume remove-brick " + volumeName); for (String brickDir : bricks) { diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/ServerUtil.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/ServerUtil.java index ed1aea75..ed77def3 100644 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/ServerUtil.java +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/ServerUtil.java @@ -42,6 +42,7 @@ import org.springframework.stereotype.Component; import com.gluster.storage.management.core.constants.CoreConstants; import com.gluster.storage.management.core.exceptions.ConnectionException; import com.gluster.storage.management.core.exceptions.GlusterRuntimeException; +import com.gluster.storage.management.core.model.Server; import com.gluster.storage.management.core.model.Status; import com.gluster.storage.management.core.response.GenericResponse; import com.gluster.storage.management.core.utils.ProcessResult; @@ -76,6 +77,21 @@ public class ServerUtil { String scriptPath = servletContext.getRealPath(SCRIPT_DIR) + CoreConstants.FILE_SEPARATOR + scriptName; return scriptPath; } + + /** + * Fetch details of the given server. The server name must be populated in the object before calling this method. + * + * @param server + * Server whose details are to be fetched + */ + public void fetchServerDetails(Server server) { + // fetch standard server details like cpu, disk, memory details + Object response = executeOnServer(true, server.getName(), "get_server_details.py --only-data-disks", Server.class); + if (response instanceof Status) { + throw new GlusterRuntimeException(((Status)response).getMessage()); + } + server.copyFrom((Server) response); // Update the details in <Server> object + } /** * Executes given command on given server diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/SshUtil.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/SshUtil.java index 5f8b88f6..d56cd47c 100644 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/SshUtil.java +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/SshUtil.java @@ -20,14 +20,14 @@ package com.gluster.storage.management.server.utils; import java.io.BufferedReader; import java.io.File; -import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.util.Arrays; -import java.util.Date; +import org.apache.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import ch.ethz.ssh2.ChannelCondition; @@ -61,6 +61,15 @@ public class SshUtil { private static final String USER_NAME = "root"; // TODO: Make default password configurable private static final String DEFAULT_PASSWORD = "syst3m"; + + private static final Logger logger = Logger.getLogger(SshUtil.class); + + @Autowired + private Integer sshConnectTimeout; + @Autowired + private Integer sshKexTimeout; + @Autowired + private Integer sshExecTimeout; public boolean hasDefaultPassword(String serverName) { try { @@ -209,29 +218,28 @@ public class SshUtil { Connection conn; conn = new Connection(serverName); try { - // tcp connection timeout = 3 sec, ssh connection timeout = 10 sec - conn.connect(null, 3000, 10000); + conn.connect(null, sshConnectTimeout, sshKexTimeout); } catch (IOException e) { - e.printStackTrace(); + logger.error("Couldn't establish SSH connection with server [" + serverName + "]", e); throw new ConnectionException("Exception while creating SSH connection with server [" + serverName + "]", e); } return conn; } - private boolean wasTerminated(int condition) { - return ((condition | ChannelCondition.EXIT_SIGNAL) == condition); - } - private boolean hasErrors(int condition, Session session) { return (hasErrorStream(condition) || (exitedGracefully(condition) && exitedWithError(session))); } + + private boolean timedOut(int condition) { + return (condition == ChannelCondition.TIMEOUT); + } private boolean exitedWithError(Session session) { return session.getExitStatus() != ProcessResult.SUCCESS; } private boolean exitedGracefully(int condition) { - return (condition | ChannelCondition.EXIT_STATUS) == condition; + return (condition == ChannelCondition.EXIT_STATUS); } private boolean hasErrorStream(int condition) { @@ -250,8 +258,10 @@ public class SshUtil { session.close(); return result; } catch (IOException e) { - throw new GlusterRuntimeException("Exception while executing command [" + command + "] on [" - + sshConnection.getHostname() + "]", e); + String errMsg = "Exception while executing command [" + command + "] on [" + sshConnection.getHostname() + + "]"; + logger.error(errMsg, e); + throw new GlusterRuntimeException(errMsg, e); } } @@ -259,41 +269,51 @@ public class SshUtil { // Wait for program to come out either // a) gracefully with an exit status, OR // b) because of a termination signal - int condition = session.waitForCondition(ChannelCondition.EXIT_SIGNAL | ChannelCondition.EXIT_STATUS, 5000); + // c) command takes to long to exit (timeout) + int condition = session.waitForCondition(ChannelCondition.EXIT_SIGNAL | ChannelCondition.EXIT_STATUS, + sshExecTimeout); StringBuilder output = new StringBuilder(); try { - readFromStream(stdoutReader, output); - if (hasErrors(condition, session)) { - readFromStream(stderrReader, output); + if(!timedOut(condition)) { + readFromStream(stdoutReader, output); + if (hasErrors(condition, session)) { + readFromStream(stderrReader, output); + } } - return prepareProcessResult(session, condition, output); + return prepareProcessResult(session, condition, output.toString().trim()); } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return null; + String errMsg = "Error while reading output stream from SSH connection!"; + logger.error(errMsg, e); + return new ProcessResult(ProcessResult.FAILURE, errMsg); } } - private ProcessResult prepareProcessResult(Session session, int condition, StringBuilder output) { + private ProcessResult prepareProcessResult(Session session, int condition, String output) { ProcessResult result = null; - if (wasTerminated(condition)) { - result = new ProcessResult(ProcessResult.FAILURE, output.toString()); - } else { + switch(condition) { + case ChannelCondition.TIMEOUT: + result = new ProcessResult(ProcessResult.FAILURE, "Command timed out!"); + break; + case ChannelCondition.EXIT_SIGNAL: + // terminated + result = new ProcessResult(ProcessResult.FAILURE, output); + break; + default: if (hasErrors(condition, session)) { Integer exitStatus = session.getExitStatus(); int statusCode = (exitStatus == null ? ProcessResult.FAILURE : exitStatus); - result = new ProcessResult(statusCode, output.toString()); + result = new ProcessResult(statusCode, output); } else { - result = new ProcessResult(ProcessResult.SUCCESS, output.toString()); + result = new ProcessResult(ProcessResult.SUCCESS, output); } + break; } return result; } - private void readFromStream(BufferedReader streamReader, StringBuilder output) throws IOException, - UnsupportedEncodingException { + private void readFromStream(BufferedReader streamReader, StringBuilder output) throws IOException { while (true) { String line = streamReader.readLine(); if (line == null) { diff --git a/src/com.gluster.storage.management.server/src/log4j.properties b/src/com.gluster.storage.management.server/src/log4j.properties index d7712c96..f84009d3 100644 --- a/src/com.gluster.storage.management.server/src/log4j.properties +++ b/src/com.gluster.storage.management.server/src/log4j.properties @@ -7,6 +7,13 @@ log4j.appender.CONSOLE.threshold=DEBUG log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout log4j.appender.CONSOLE.layout.ConversionPattern=%d{dd MMM, yyyy HH:mm:ss} %p: %c %t - %m%n +log4j.appender.R=org.apache.log4j.RollingFileAppender +log4j.appender.R.File=${catalina.home}/logs/tomcat.log +log4j.appender.R.MaxFileSize=10MB +log4j.appender.R.MaxBackupIndex=10 +log4j.appender.R.layout=org.apache.log4j.PatternLayout +log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n + log4j.logger.org.springframework=ERROR log4j.logger.org.springframework.aop=DEBUG log4j.logger.com.gluster=INFO
\ No newline at end of file diff --git a/src/com.gluster.storage.management.server/src/spring/gluster-server-base.xml b/src/com.gluster.storage.management.server/src/spring/gluster-server-base.xml index 3c7d6436..700d996f 100644 --- a/src/com.gluster.storage.management.server/src/spring/gluster-server-base.xml +++ b/src/com.gluster.storage.management.server/src/spring/gluster-server-base.xml @@ -21,6 +21,20 @@ <constructor-arg value="vmware" /> </bean> + <!-- SSH timeouts - all in milliseconds. zero means no timeout. --> + <!-- Connect the underlying TCP socket to the server with the given timeout value (SSH) --> + <bean id="sshConnectTimeout" class="java.lang.Integer"> + <constructor-arg value="10000" /> + </bean> + <!-- Timeout for complete connection establishment (SSH) --> + <bean id="sshKexTimeout" class="java.lang.Integer"> + <constructor-arg value="60000" /> + </bean> + <!-- Command execution timeout (SSH) --> + <bean id="sshExecTimeout" class="java.lang.Integer"> + <constructor-arg value="120000" /> + </bean> + <!-- Gluster Management Gateway Version --> <bean id="appVersion" class="java.lang.String"> <constructor-arg value="1.0.0" /> |
