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 | |
| parent | 19ed9b4866499d9c264c8db8fc616fb5a5e36ce3 (diff) | |
| parent | 40d4024c47ca1e1e15e2500a5412791d364bd8b0 (diff) | |
Merge remote branch 'upstream/master'
100 files changed, 2650 insertions, 1010 deletions
diff --git a/src/com.gluster.storage.management.client/.classpath b/src/com.gluster.storage.management.client/.classpath index d216a8fe..218503d5 100644 --- a/src/com.gluster.storage.management.client/.classpath +++ b/src/com.gluster.storage.management.client/.classpath @@ -1,8 +1,8 @@ <?xml version="1.0" encoding="UTF-8"?> <classpath> <classpathentry exported="true" kind="lib" path="keystore/"/> - <classpathentry exported="true" kind="lib" path="lib/jersey-1.5/jersey-client-1.5.jar" sourcepath="/data/downloads/sun/jersey/sources/jersey-client-1.5-sources.jar"/> - <classpathentry exported="true" kind="lib" path="lib/jersey-1.5/jersey-core-1.5.jar" sourcepath="/data/downloads/sun/jersey/sources/jersey-core-1.5-sources.jar"/> + <classpathentry exported="true" kind="lib" path="lib/jersey-1.5/jersey-client-1.5.jar" sourcepath="/home/selvam/sources/jersey/jersey-client-1.5-sources.jar"/> + <classpathentry exported="true" kind="lib" path="lib/jersey-1.5/jersey-core-1.5.jar" sourcepath="/home/selvam/sources/jersey/jersey-core-1.5-sources.jar"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/> <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> <classpathentry excluding="keystore/" kind="src" path="src"/> diff --git a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/AbstractClient.java b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/AbstractClient.java index 9eaaca93..6f4ba050 100644 --- a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/AbstractClient.java +++ b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/AbstractClient.java @@ -9,6 +9,7 @@ import static com.gluster.storage.management.client.constants.ClientConstants.TR import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.net.URI;
import java.security.KeyStore;
import javax.net.ssl.HostnameVerifier;
@@ -21,6 +22,7 @@ import javax.ws.rs.core.MultivaluedMap; import com.gluster.storage.management.client.utils.ClientUtil;
import com.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import com.gluster.storage.management.core.model.TaskInfo;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.UniformInterfaceException;
@@ -31,6 +33,7 @@ import com.sun.jersey.api.representation.Form; import com.sun.jersey.client.urlconnection.HTTPSProperties;
import com.sun.jersey.core.util.MultivaluedMapImpl;
+
public abstract class AbstractClient {
private static final String HTTP_HEADER_AUTH = "Authorization";
protected static final MultivaluedMap<String, String> NO_PARAMS = new MultivaluedMapImpl();
@@ -39,6 +42,7 @@ public abstract class AbstractClient { protected WebResource resource;
private String securityToken;
private String authHeader;
+ private Client client;
/**
* This constructor will work only after the data model manager has been initialized.
@@ -59,11 +63,16 @@ public abstract class AbstractClient { this.clusterName = clusterName;
setSecurityToken(securityToken);
- SSLContext context = initializeSSLContext();
- DefaultClientConfig config = createClientConfig(context);
+ createClient();
// this must be after setting clusterName as sub-classes may refer to cluster name in the getResourcePath method
- resource = Client.create(config).resource(ClientUtil.getServerBaseURI()).path(getResourcePath());
+ resource = client.resource(ClientUtil.getServerBaseURI()).path(getResourcePath());
+ }
+
+ private void createClient() {
+ SSLContext context = initializeSSLContext();
+ DefaultClientConfig config = createClientConfig(context);
+ client = Client.create(config);
}
private DefaultClientConfig createClientConfig(SSLContext context) {
@@ -121,12 +130,12 @@ public abstract class AbstractClient { * @return Object of responseClass received as a result of the GET request
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
- private Object fetchResource(WebResource res, MultivaluedMap<String, String> queryParams, Class responseClass) {
+ private <T> T fetchResource(WebResource res, MultivaluedMap<String, String> queryParams, Class<T> responseClass) {
try {
return res.queryParams(queryParams)
.header(HTTP_HEADER_AUTH, authHeader).accept(MediaType.APPLICATION_XML).get(responseClass);
} catch(UniformInterfaceException e) {
- throw new GlusterRuntimeException(e.getResponse().getEntity(String.class));
+ throw new GlusterRuntimeException(e.getResponse().getEntity(String.class), e);
}
}
@@ -139,13 +148,14 @@ public abstract class AbstractClient { }
InputStream inputStream = response.getEntityInputStream();
- byte[] data = new byte[inputStream.available()];
- inputStream.read(data);
+ FileOutputStream outputStream = new FileOutputStream(filePath);
+
+ int c;
+ while((c = inputStream.read()) != -1) {
+ outputStream.write(c);
+ }
inputStream.close();
-
- FileOutputStream os = new FileOutputStream(filePath);
- os.write(data);
- os.close();
+ outputStream.close();
} catch (IOException e) {
throw new GlusterRuntimeException("Error while downloading resource [" + res.getURI().getPath() + "]", e);
}
@@ -262,9 +272,13 @@ public abstract class AbstractClient { postRequest(resource.path(subResourceName), form);
}
- private void putRequest(WebResource resource, Form form) {
+ private ClientResponse putRequest(WebResource resource, Form form) {
try {
- prepareFormRequestBuilder(resource).put(form);
+ ClientResponse response = prepareFormRequestBuilder(resource).put(ClientResponse.class, form);
+ if(response.getStatus() >= 300) {
+ throw new GlusterRuntimeException(response.getEntity(String.class));
+ }
+ return response;
} catch (UniformInterfaceException e) {
throw new GlusterRuntimeException(e.getResponse().getEntity(String.class));
}
@@ -286,6 +300,12 @@ public abstract class AbstractClient { protected void putRequest(String subResourceName, Form form) {
putRequest(resource.path(subResourceName), form);
}
+
+
+ protected URI putRequestURI(String subResourceName, Form form) {
+ ClientResponse response = putRequest(resource.path(subResourceName), form);
+ return response.getLocation();
+ }
/**
* Submits given Form using PUT method to the given sub-resource and returns the object received as response
@@ -353,4 +373,13 @@ public abstract class AbstractClient { this.securityToken = securityToken;
authHeader = "Basic " + securityToken;
}
+
+ /**
+ * @param uri The URI to be fetched using GET API
+ * @param responseClass Expected type of response object
+ * @return Object of the given class
+ */
+ protected <T> T fetchResource(URI uri, Class<T> responseClass) {
+ return fetchResource(client.resource(uri), NO_PARAMS, responseClass);
+ }
}
diff --git a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/ClustersClient.java b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/ClustersClient.java index dadeadf8..31809c75 100644 --- a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/ClustersClient.java +++ b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/ClustersClient.java @@ -74,27 +74,29 @@ public class ClustersClient extends AbstractClient { public static void main(String args[]) { UsersClient usersClient = new UsersClient(); - Status authStatus = usersClient.authenticate("gluster", "gluster"); - if (authStatus.isSuccess()) { - ClustersClient client = new ClustersClient(); - client.setSecurityToken(usersClient.getSecurityToken()); - System.out.println(client.getClusterNames()); - try { - client.createCluster("test1"); - } catch(GlusterRuntimeException e) { - System.out.println(e.getMessage()); - } - - System.out.println(client.getClusterNames()); - - try { - client.deleteCluster("test1"); - } catch (GlusterRuntimeException e) { - System.out.println(e.getMessage()); - } - System.out.println(client.getClusterNames()); - } else { - System.out.println("authentication failed: " + authStatus); + + try { + usersClient.authenticate("gluster", "gluster"); + } catch(Exception e) { + e.printStackTrace(); } + + ClustersClient client = new ClustersClient(); + client.setSecurityToken(usersClient.getSecurityToken()); + System.out.println(client.getClusterNames()); + try { + client.createCluster("test1"); + } catch (GlusterRuntimeException e) { + System.out.println(e.getMessage()); + } + + System.out.println(client.getClusterNames()); + + try { + client.deleteCluster("test1"); + } catch (GlusterRuntimeException e) { + System.out.println(e.getMessage()); + } + System.out.println(client.getClusterNames()); } } diff --git a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/DiscoveredServersClient.java b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/DiscoveredServersClient.java index e055a2dd..3704e2ff 100644 --- a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/DiscoveredServersClient.java +++ b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/DiscoveredServersClient.java @@ -18,13 +18,17 @@ *******************************************************************************/ package com.gluster.storage.management.client; +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.List; + import javax.ws.rs.core.MultivaluedMap; import com.gluster.storage.management.core.model.Server; 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 static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_PATH_DISCOVERED_SERVERS; +import com.gluster.storage.management.core.response.ServerNameListResponse; import com.sun.jersey.core.util.MultivaluedMapImpl; public class DiscoveredServersClient extends AbstractClient { @@ -43,38 +47,36 @@ public class DiscoveredServersClient extends AbstractClient { } @SuppressWarnings("rawtypes") - private Object getDiscoveredServers(Boolean getDetails, Class responseClass) { + private Object getDiscoveredServers(Boolean details, Class responseClass) { MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl(); - queryParams.putSingle("details", getDetails.toString()); + queryParams.putSingle(QUERY_PARAM_DETAILS, details.toString()); return fetchResource(queryParams, responseClass); } - public StringListResponse getDiscoveredServerNames() { - - return (StringListResponse) getDiscoveredServers(Boolean.FALSE, StringListResponse.class); + public List<String> getDiscoveredServerNames() { + return ((ServerNameListResponse) getDiscoveredServers(Boolean.FALSE, ServerNameListResponse.class)) + .getServerNames(); } - public ServerListResponse getDiscoveredServerDetails() { - return (ServerListResponse) getDiscoveredServers(Boolean.TRUE, ServerListResponse.class); + public List<Server> getDiscoveredServerDetails() { + return ((ServerListResponse) getDiscoveredServers(Boolean.TRUE, ServerListResponse.class)).getServers(); } - @SuppressWarnings("unchecked") public Server getServer(String serverName) { - GenericResponse<Server> response = (GenericResponse<Server>) fetchSubResource(serverName, GenericResponse.class); - return response.getData(); + return (Server) fetchSubResource(serverName, Server.class); } public static void main(String[] args) { UsersClient usersClient = new UsersClient(); - if (usersClient.authenticate("gluster", "gluster").isSuccess()) { + try { + usersClient.authenticate("gluster", "gluster"); DiscoveredServersClient serverResource = new DiscoveredServersClient(usersClient.getSecurityToken()); - StringListResponse discoveredServerNames = serverResource.getDiscoveredServerNames(); - System.out.println(discoveredServerNames.getData()); - ServerListResponse discoveredServers = serverResource.getDiscoveredServerDetails(); - System.out.println(discoveredServers.getData()); - - // Server serverDetails = ServerResource.getServer("localhost"); - // System.out.println(serverDetails.getName()); + List<String> discoveredServerNames = serverResource.getDiscoveredServerNames(); + System.out.println(discoveredServerNames); + List<Server> discoveredServers = serverResource.getDiscoveredServerDetails(); + System.out.println(discoveredServers); + } catch(Exception e) { + e.printStackTrace(); } } } diff --git a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/GlusterDataModelManager.java b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/GlusterDataModelManager.java index 3c5aedf5..9705501a 100644 --- a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/GlusterDataModelManager.java +++ b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/GlusterDataModelManager.java @@ -21,6 +21,7 @@ package com.gluster.storage.management.client; import java.util.ArrayList; import java.util.List; import java.util.Map.Entry; +import java.util.Set; import com.gluster.storage.management.core.exceptions.GlusterRuntimeException; import com.gluster.storage.management.core.model.Brick; @@ -35,15 +36,13 @@ import com.gluster.storage.management.core.model.GlusterServer; import com.gluster.storage.management.core.model.Server; 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.model.Volume; import com.gluster.storage.management.core.model.Volume.TRANSPORT_TYPE; import com.gluster.storage.management.core.model.Volume.VOLUME_STATUS; import com.gluster.storage.management.core.model.Volume.VOLUME_TYPE; import com.gluster.storage.management.core.model.VolumeOptionInfo; -import com.gluster.storage.management.core.response.GlusterServerListResponse; -import com.gluster.storage.management.core.response.ServerListResponse; -import com.gluster.storage.management.core.response.VolumeListResponse; -import com.gluster.storage.management.core.response.VolumeOptionInfoListResponse; public class GlusterDataModelManager { private static GlusterDataModelManager instance = new GlusterDataModelManager(); @@ -92,7 +91,6 @@ public class GlusterDataModelManager { initializeAutoDiscoveredServers(cluster); // initializeDisks(); - initializeTasks(cluster); initializeAlerts(cluster); initializeVolumeOptionsDefaults(); @@ -105,14 +103,7 @@ public class GlusterDataModelManager { } private void initializeAutoDiscoveredServers(Cluster cluster) { - ServerListResponse discoveredServerListResponse = new DiscoveredServersClient(securityToken) - .getDiscoveredServerDetails(); - Status status = discoveredServerListResponse.getStatus(); - if (!status.isSuccess() && !status.isPartSuccess()) { - // TODO: Find a way to show warning in case of part success - throw new GlusterRuntimeException(discoveredServerListResponse.getStatus().getMessage()); - } - cluster.setAutoDiscoveredServers(discoveredServerListResponse.getData()); + cluster.setAutoDiscoveredServers(new DiscoveredServersClient(securityToken).getDiscoveredServerDetails()); } private void initializeVolumes(Cluster cluster) { @@ -125,10 +116,40 @@ public class GlusterDataModelManager { } public void initializeTasks(Cluster cluster) { - List<TaskInfo> taskInfoList = new TasksClient(cluster.getName()).getAllTasks(); + // List<TaskInfo> taskInfoList = new TasksClient(cluster.getName()).getAllTasks(); + List<TaskInfo> taskInfoList = getDummyTasks(); cluster.setTaskInfoList(taskInfoList); } + private List<TaskInfo> getDummyTasks() { + List<TaskInfo> taskInfoList = new ArrayList<TaskInfo>(); + + // Task #1 + TaskInfo taskInfo = new TaskInfo(); + taskInfo.setType(TASK_TYPE.BRICK_MIGRATE); + taskInfo.setName("Migrate Brick-music"); + taskInfo.setCanPause(true); + taskInfo.setCanStop(true); + taskInfo.setStatus(new TaskStatus(new Status(Status.STATUS_CODE_RUNNING, ""))); + + taskInfo.getStatus().setMessage("Migrating file xxxxx to yyyy"); + taskInfo.setDescription("Migrate Brick on volume [music] from /export/adb/music to /export/sdc/music."); + taskInfoList.add(taskInfo); + // Task #2 + taskInfo = new TaskInfo(); + taskInfo.setType(TASK_TYPE.DISK_FORMAT); + taskInfo.setName("Format Disk-server1:sdc"); + taskInfo.setCanPause(false); + taskInfo.setCanStop(false); + taskInfo.setStatus( new TaskStatus(new Status(Status.STATUS_CODE_FAILURE, ""))); + taskInfo.getStatus().setMessage("Format completes 80% ..."); + taskInfo.setDescription("Formatting disk server1:sdc."); + taskInfoList.add(taskInfo); + + + return taskInfoList; + } + public void initializeAlerts(Cluster cluster) { cluster.setAlerts(new AlertsClient(cluster.getName()).getAllAlerts()); } @@ -182,7 +203,7 @@ public class GlusterDataModelManager { Disk disk = null; List<Disk> volumeDisks = new ArrayList<Disk>(); for (Brick brick : volume.getBricks()) { - disk = getDisk(brick.getDiskName()); + disk = getDisk(brick.getServerName() + ":" + brick.getDiskName()); // disk = new Disk(); // disk.setServerName(brick.getServerName()); // disk.setName(brick.getDiskName()); @@ -319,7 +340,7 @@ public class GlusterDataModelManager { } } - public void removeBricks(Volume volume, List<Brick> bricks) { + public void removeBricks(Volume volume, Set<Brick> bricks) { for (ClusterListener listener : listeners) { listener.volumeChanged(volume, new Event(EVENT_TYPE.BRICKS_REMOVED, bricks)); } @@ -341,6 +362,29 @@ public class GlusterDataModelManager { } } + public void addTask(TaskInfo taskInfo) { + Cluster cluster = model.getCluster(); + cluster.addTaskInfo(taskInfo); + for (ClusterListener listener : listeners) { + listener.taskAdded(taskInfo); + } + } + + // Updating the Task + public void updateTask(TaskInfo taskInfo) { + for (ClusterListener listener : listeners) { + listener.taskUpdated(taskInfo); + } + } + + public void removeTask(TaskInfo taskInfo) { + Cluster cluster = model.getCluster(); + cluster.removeTaskInfo(taskInfo); + for (ClusterListener listener : listeners) { + listener.taskAdded(taskInfo); + } + } + public List<VolumeOptionInfo> getVolumeOptionsDefaults() { return volumeOptionsDefaults; } @@ -421,4 +465,5 @@ public class GlusterDataModelManager { } return volumeNames; } + } diff --git a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/GlusterServersClient.java b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/GlusterServersClient.java index b525da01..b6d0a426 100644 --- a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/GlusterServersClient.java +++ b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/GlusterServersClient.java @@ -62,13 +62,18 @@ public class GlusterServersClient extends AbstractClient { postRequest(form); } + public void initializeDisk(String serverName, String diskName) { + putRequest(serverName + "/" + RESTConstants.RESOURCE_DISKS + "/" + diskName); + } + public void removeServer(String serverName) { deleteSubResource(serverName); } public static void main(String[] args) { UsersClient usersClient = new UsersClient(); - if (usersClient.authenticate("gluster", "gluster").isSuccess()) { + try { + usersClient.authenticate("gluster", "gluster"); GlusterServersClient glusterServersClient = new GlusterServersClient(usersClient.getSecurityToken(), "cluster1"); List<GlusterServer> glusterServers = glusterServersClient.getServers(); for (GlusterServer server : glusterServers) { @@ -79,6 +84,8 @@ public class GlusterServersClient extends AbstractClient { Server srv = new Server(); srv.setName("server3"); glusterServersClient.addServer(srv); + } catch(Exception e) { + e.printStackTrace(); } } } diff --git a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/TasksClient.java b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/TasksClient.java index b5ee1d1c..46077371 100644 --- a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/TasksClient.java +++ b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/TasksClient.java @@ -20,21 +20,23 @@ */ package com.gluster.storage.management.client; +import java.net.URI; import java.util.List; import javax.ws.rs.core.MultivaluedMap; 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.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.sun.jersey.api.representation.Form; import com.sun.jersey.core.util.MultivaluedMapImpl; public class TasksClient extends AbstractClient { + public TasksClient() { + super(); + } + public TasksClient(String clusterName) { super(clusterName); } @@ -48,14 +50,8 @@ public class TasksClient extends AbstractClient { return RESTConstants.RESOURCE_PATH_CLUSTERS + "/" + clusterName + "/" + RESTConstants.RESOURCE_TASKS + "/"; } - @SuppressWarnings("unchecked") public List<TaskInfo> getAllTasks() { // TaskListResponse get only the list of taskInfo not list of Tasks - TaskListResponse response = (TaskListResponse) fetchResource(TaskListResponse.class); - if (response.getStatus().isSuccess()) { - return (List<TaskInfo>) response.getData(); - } else { - throw new GlusterRuntimeException("Exception on fetching tasks [" + response.getStatus().getMessage() + "]"); - } + return ((TaskInfoListResponse) fetchResource(TaskInfoListResponse.class)).getTaskList(); } // see startMigration @ VolumesClient, etc @@ -79,6 +75,13 @@ public class TasksClient extends AbstractClient { putRequest(taskId, form); } + + public void commitTask(String taskId) { + Form form = new Form(); + form.add(RESTConstants.FORM_PARAM_OPERATION, RESTConstants.TASK_COMMIT); + + putRequest(taskId, form); + } public void getTaskStatus(String taskId) { Form form = new Form(); @@ -90,7 +93,11 @@ public class TasksClient extends AbstractClient { public void deleteTask(String taskId) { MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl(); queryParams.add(RESTConstants.FORM_PARAM_OPERATION, RESTConstants.TASK_DELETE); - + deleteSubResource(taskId, queryParams); } + + public TaskInfo getTaskInfo(URI uri) { + return ((TaskInfo) fetchResource(uri, TaskInfo.class)); + } } diff --git a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/UsersClient.java b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/UsersClient.java index 84ed4e4c..c839a15a 100644 --- a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/UsersClient.java +++ b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/UsersClient.java @@ -22,6 +22,7 @@ import java.net.ConnectException; import javax.ws.rs.core.Response; +import com.gluster.storage.management.core.exceptions.GlusterRuntimeException; import com.gluster.storage.management.core.model.Status; import com.sun.jersey.api.client.UniformInterfaceException; import com.sun.jersey.api.representation.Form; @@ -40,60 +41,59 @@ public class UsersClient extends AbstractClient { super(); } - public Status authenticate(String user, String password) { + public void authenticate(String user, String password) { setSecurityToken(generateSecurityToken(user, password)); try { - Status authStatus = (Status) fetchSubResource(user, Status.class); - if (!authStatus.isSuccess()) { - // authentication failed. clear security token. - setSecurityToken(null); - } - return authStatus; - } catch (UniformInterfaceException e) { - if ((e.getResponse().getStatus() == Response.Status.UNAUTHORIZED.getStatusCode())) { - // authentication failed. clear security token. - setSecurityToken(null); - return new Status(Status.STATUS_CODE_FAILURE, "Invalid user id or password!"); - } else { + fetchSubResource(user, String.class); + } catch (RuntimeException e) { + Throwable cause = e.getCause(); + if(cause == null) { throw e; } - } catch (Exception e) { - // authentication failed. clear security token. - setSecurityToken(null); - Throwable cause = e.getCause(); - if(cause != null && cause instanceof ConnectException) { - return new Status(Status.STATUS_CODE_FAILURE, "Couldn't connect to Gluster Management Gateway!"); + if (cause instanceof UniformInterfaceException) { + UniformInterfaceException e1 = (UniformInterfaceException) cause; + if ((e1.getResponse().getStatus() == Response.Status.UNAUTHORIZED.getStatusCode())) { + // authentication failed. clear security token. + setSecurityToken(null); + throw new GlusterRuntimeException("Invalid user id or password!"); + } else { + // TODO: Log the exception + throw new GlusterRuntimeException("Exception during authentication: [" + + e1.getResponse().getStatus() + "]"); + } + } else if(cause instanceof ConnectException) { + throw new GlusterRuntimeException("Couldn't connect to Gluster Management Gateway!"); + } else { + throw new GlusterRuntimeException("Exception during authentication: [" + e.getMessage() + "]"); } - return new Status(Status.STATUS_CODE_FAILURE, "Exception during authentication: [" + e.getMessage() + "]"); } } - public boolean changePassword(String user, String oldPassword, String newPassword) { + public void changePassword(String user, String oldPassword, String newPassword) { setSecurityToken(generateSecurityToken(user, oldPassword)); Form form = new Form(); form.add(FORM_PARAM_OLD_PASSWORD, oldPassword); form.add(FORM_PARAM_NEW_PASSWORD, newPassword); - try { - putRequest(user, form); - return true; - } catch (Exception e) { - return false; - } + putRequest(user, form); } public static void main(String[] args) { - UsersClient authClient = new UsersClient(); - - // authenticate user - System.out.println(authClient.authenticate("gluster", "gluster")); - - // change password to gluster1 - System.out.println(authClient.changePassword("gluster", "gluster", "gluster1")); - - // change it back to gluster - System.out.println(authClient.changePassword("gluster", "gluster1", "gluster")); +// UsersClient authClient = new UsersClient(); +// +// // authenticate user +// authClient.authenticate("gluster", "gluster"); +// +// // change password to gluster1 +// authClient.changePassword("gluster", "gluster", "gluster1"); +// +// // change it back to gluster +// authClient.changePassword("gluster", "gluster1", "gluster"); +// +// System.out.println("success"); + System.out.println(new String(Base64.encode("abcdefghijklmnopqrstuvwxyz"))); + System.out.println(new String(Base64.decode("YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo="))); } /* diff --git a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/VolumesClient.java b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/VolumesClient.java index d237f010..b5d2711a 100644 --- a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/VolumesClient.java +++ b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/VolumesClient.java @@ -29,8 +29,10 @@ import static com.gluster.storage.management.core.constants.RESTConstants.FORM_P 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 java.net.URI; import java.util.Date; import java.util.List; +import java.util.Set; import javax.ws.rs.core.MultivaluedMap; @@ -38,6 +40,7 @@ import com.gluster.storage.management.core.constants.CoreConstants; import com.gluster.storage.management.core.constants.GlusterConstants; import com.gluster.storage.management.core.constants.RESTConstants; import com.gluster.storage.management.core.model.Brick; +import com.gluster.storage.management.core.model.TaskInfo; import com.gluster.storage.management.core.model.Volume; import com.gluster.storage.management.core.model.VolumeLogMessage; import com.gluster.storage.management.core.model.VolumeOptionInfo; @@ -175,7 +178,7 @@ public class VolumesClient extends AbstractClient { downloadSubResource(volumeName + "/" + RESTConstants.RESOURCE_LOGS + "/" + RESTConstants.RESOURCE_DOWNLOAD, filePath); } - public void removeBricks(String volumeName, List<Brick> BrickList, boolean deleteOption) { + public void removeBricks(String volumeName, Set<Brick> BrickList, boolean deleteOption) { String bricks = StringUtil.collectionToString(GlusterCoreUtil.getQualifiedBrickList(BrickList), ","); MultivaluedMap<String, String> queryParams = prepareRemoveBrickQueryParams(volumeName, bricks, deleteOption); deleteSubResource(volumeName + "/" + RESTConstants.RESOURCE_BRICKS, queryParams); @@ -220,22 +223,45 @@ public class VolumesClient extends AbstractClient { return queryParams; } - public void startMigration(String volumeName, String brickFrom, String brickTo, Boolean autoCommit) { + public URI startMigration(String volumeName, String brickFrom, String brickTo, Boolean autoCommit) { Form form = new Form(); form.add(RESTConstants.FORM_PARAM_SOURCE, brickFrom); form.add(RESTConstants.FORM_PARAM_TARGET, brickTo); form.add(RESTConstants.FORM_PARAM_OPERATION, RESTConstants.TASK_START); form.add(RESTConstants.FORM_PARAM_AUTO_COMMIT, autoCommit); - - putRequest(volumeName + "/" + RESTConstants.RESOURCE_BRICKS, form); + return putRequestURI(volumeName + "/" + RESTConstants.RESOURCE_BRICKS, form); + } + + public void rebalanceStart(String volumeName, Boolean fixLayout, Boolean migrateData, Boolean forcedDataMigrate) { + Form form = new Form(); + form.add(RESTConstants.FORM_PARAM_OPERATION, RESTConstants.TASK_REBALANCE_START); + form.add(RESTConstants.FORM_PARAM_FIX_LAYOUT, fixLayout); + form.add(RESTConstants.FORM_PARAM_MIGRATE_DATA, migrateData); + form.add(RESTConstants.FORM_PARAM_FORCED_DATA_MIGRATE, forcedDataMigrate); + putRequest(volumeName, form); + } + + public void rebalanceStatus(String volumeName) { + Form form = new Form(); + form.add(RESTConstants.FORM_PARAM_OPERATION, RESTConstants.TASK_REBALANCE_STATUS); + putRequest(volumeName, form); + } + + public void rebalanceStop(String volumeName) { + Form form = new Form(); + form.add(RESTConstants.FORM_PARAM_OPERATION, RESTConstants.TASK_REBALANCE_STOP); + putRequest(volumeName, form); } public static void main(String[] args) { UsersClient usersClient = new UsersClient(); - if (usersClient.authenticate("gluster", "gluster").isSuccess()) { + try { + usersClient.authenticate("gluster", "gluster"); VolumesClient client = new VolumesClient(usersClient.getSecurityToken()); System.out.println(client.getAllVolumes()); // client.downloadLogs("vol1", "/tmp/temp1.tar.gz"); + } catch(Exception e) { + e.printStackTrace(); } } } diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/constants/RESTConstants.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/constants/RESTConstants.java index a2d222a8..527ae2a1 100644 --- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/constants/RESTConstants.java +++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/constants/RESTConstants.java @@ -25,6 +25,7 @@ package com.gluster.storage.management.core.constants; */ public class RESTConstants { // REST Resource paths + public static final String RESOURCE_PATH_USERS = "/users"; public static final String RESOURCE_PATH_CLUSTERS = "/clusters"; public static final String RESOURCE_PATH_DISCOVERED_SERVERS = "/discoveredservers"; @@ -44,8 +45,12 @@ public class RESTConstants { public static final String TASK_PAUSE = "pause"; public static final String TASK_RESUME = "resume"; public static final String TASK_STOP = "stop"; + public static final String TASK_COMMIT = "commit"; public static final String TASK_STATUS = "status"; public static final String TASK_DELETE = "delete"; + public static final String TASK_REBALANCE_START = "rebalanceStart"; + public static final String TASK_REBALANCE_STATUS = "rebalanceStatus"; + public static final String TASK_REBALANCE_STOP = "rebalanceStop"; public static final String FORM_PARAM_VOLUME_NAME = "name"; public static final String FORM_PARAM_VOLUME_TYPE = "volumeType"; @@ -56,7 +61,6 @@ public class RESTConstants { public static final String FORM_PARAM_ACCESS_PROTOCOLS = "accessProtocols"; public static final String FORM_PARAM_VOLUME_OPTIONS = "options"; - public static final String FORM_PARAM_CLUSTER_NAME = "clusterName"; public static final String FORM_PARAM_SERVER_NAME = "serverName"; public static final String FORM_PARAM_DISKS = "disks"; @@ -67,12 +71,17 @@ public class RESTConstants { public static final String FORM_PARAM_SOURCE = "source"; public static final String FORM_PARAM_TARGET = "target"; public static final String FORM_PARAM_AUTO_COMMIT = "autoCommit"; + public static final String FORM_PARAM_FIX_LAYOUT = "fix-layout"; + public static final String FORM_PARAM_MIGRATE_DATA = "migrate-data"; + public static final String FORM_PARAM_FORCED_DATA_MIGRATE = "forced-data-migrate"; public static final String PATH_PARAM_FORMAT = "format"; public static final String PATH_PARAM_VOLUME_NAME = "volumeName"; public static final String PATH_PARAM_CLUSTER_NAME = "clusterName"; public static final String PATH_PARAM_SERVER_NAME = "serverName"; public static final String PATH_PARAM_TASK_ID = "taskId"; + public static final String PATH_PARAM_DISK_NAME = "diskName"; + public static final String PATH_PARAM_USER = "user"; public static final String QUERY_PARAM_BRICK_NAME = "brickName"; public static final String QUERY_PARAM_DISKS = "disks"; @@ -85,6 +94,7 @@ public class RESTConstants { public static final String QUERY_PARAM_TO_TIMESTAMP = "toTimestamp"; public static final String QUERY_PARAM_DOWNLOAD = "download"; public static final String QUERY_PARAM_SERVER_NAME = "serverName"; + public static final String QUERY_PARAM_DETAILS = "details"; public static final String FORMAT_XML = "xml"; public static final String FORMAT_JSON = "json"; diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/exceptions/GlusterValidationException.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/exceptions/GlusterValidationException.java new file mode 100644 index 00000000..ca5e01f8 --- /dev/null +++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/exceptions/GlusterValidationException.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * 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.core.exceptions; + +public class GlusterValidationException extends GlusterRuntimeException { + private static final long serialVersionUID = 1L; + + public GlusterValidationException(String message) { + super(message); + } +} diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/Cluster.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/Cluster.java index 0c094e99..d6757cba 100644 --- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/Cluster.java +++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/Cluster.java @@ -115,6 +115,10 @@ public class Cluster extends Entity { public void addTaskInfo(TaskInfo taskInfo) { this.taskInfoList.add(taskInfo); } + + public void removeTaskInfo(TaskInfo taskInfo) { + this.taskInfoList.remove(taskInfo); + } public List<Alert> getAlerts() { return alerts; diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/ClusterListener.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/ClusterListener.java index f96116ed..71de5e23 100644 --- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/ClusterListener.java +++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/ClusterListener.java @@ -42,4 +42,10 @@ public interface ClusterListener { public void volumeCreated(Volume volume); public void volumeDeleted(Volume volume); + + public void taskAdded(TaskInfo taskInfo); + + public void taskRemoved(TaskInfo taskInfo); + + public void taskUpdated(TaskInfo taskInfo); } diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/DefaultClusterListener.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/DefaultClusterListener.java index e226d51b..d3b0e42e 100644 --- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/DefaultClusterListener.java +++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/DefaultClusterListener.java @@ -74,6 +74,24 @@ public class DefaultClusterListener implements ClusterListener { clusterChanged(); } + + @Override + public void taskAdded(TaskInfo taskInfo) { + clusterChanged(); + } + + + @Override + public void taskRemoved(TaskInfo taskInfo) { + clusterChanged(); + } + + + @Override + public void taskUpdated(TaskInfo taskInfo) { + clusterChanged(); + } + /** * This method is called by every other event method. Thus, if a view/listener is interested in performing the same * task on any change happening in the cluster data model, it can simply override this method and implement the @@ -82,4 +100,5 @@ public class DefaultClusterListener implements ClusterListener { public void clusterChanged() { } + } diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/Status.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/Status.java index 95075f78..701fe426 100644 --- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/Status.java +++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/Status.java @@ -31,6 +31,7 @@ public class Status { public static final int STATUS_CODE_RUNNING = 3; public static final int STATUS_CODE_PAUSE = 4; public static final int STATUS_CODE_WARNING = 5; + public static final int STATUS_CODE_COMMIT_PENDING = 6; public static final Status STATUS_SUCCESS = new Status(STATUS_CODE_SUCCESS, "Success"); public static final Status STATUS_FAILURE = new Status(STATUS_CODE_FAILURE, "Failure"); diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/Task.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/Task.java deleted file mode 100644 index 45eb07ba..00000000 --- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/Task.java +++ /dev/null @@ -1,83 +0,0 @@ -/** - * 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.core.model; - -public abstract class Task { - public enum TASK_TYPE { - DISK_FORMAT, BRICK_MIGRATE, VOLUME_REBALANCE - } - - public String[] TASK_TYPE_STR = { "Format Disk", "Migrate Brick", "Volume Rebalance" }; - - private TaskInfo taskInfo; - - protected String serverName; - - public Task(TASK_TYPE type, String reference) { - taskInfo = new TaskInfo(); - taskInfo.setType(type); - taskInfo.setId(getTypeStr() + "-" + reference); // construct id - taskInfo.setReference(reference); - } - - public Task(TaskInfo taskInfo) { - setTaskInfo(taskInfo); - } - - public String getTypeStr() { - return TASK_TYPE_STR[taskInfo.getType().ordinal()]; - } - - public TASK_TYPE getType() { - return getTaskInfo().getType(); - } - - public String getOnlineServer() { - return serverName; - } - - public void setOnlineServer(String serverName) { - this.serverName = serverName; - } - - public TaskInfo getTaskInfo() { - return taskInfo; - } - - public void setTaskInfo(TaskInfo info) { - this.taskInfo = info; - } - - public abstract String getId(); - - public abstract TaskInfo start(); - - public abstract TaskInfo resume(); - - public abstract TaskInfo stop(); - - public abstract TaskInfo pause(); - - public abstract TaskInfo status(); - - public abstract void setTaskDescription(); - -} diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/TaskInfo.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/TaskInfo.java index d4549146..1ce2fa04 100644 --- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/TaskInfo.java +++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/TaskInfo.java @@ -20,24 +20,31 @@ */ package com.gluster.storage.management.core.model; -import com.gluster.storage.management.core.model.Task.TASK_TYPE; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +import com.gluster.storage.management.core.utils.StringUtil; + +@XmlRootElement +public class TaskInfo extends Entity { + public enum TASK_TYPE { + DISK_FORMAT, BRICK_MIGRATE, VOLUME_REBALANCE + } -public class TaskInfo extends Status { - private String id; private TASK_TYPE type; private String reference; private String description; - private Boolean canPause; - private Boolean canStop; + private Boolean pauseSupported; + private Boolean stopSupported; + private Boolean commitSupported; private TaskStatus status; - - public String getId() { - return id; + public TaskInfo() { } - public void setId(String id) { - this.id = id; + @XmlElement(name="id") + public String getName() { + return super.getName(); } public TASK_TYPE getType() { @@ -72,20 +79,35 @@ public class TaskInfo extends Status { this.status = status; } - public Boolean getCanPause() { - return canPause; + public Boolean canPause() { + return pauseSupported; } public void setCanPause(Boolean canPause) { - this.canPause = canPause; + this.pauseSupported = canPause; } - public Boolean getCanStop() { - return canStop; + public Boolean canStop() { + return stopSupported; } public void setCanStop(Boolean canStop) { - this.canStop = canStop; + this.stopSupported = canStop; + } + + public Boolean canCommit() { + return this.commitSupported; + } + + public void setCanCommit(Boolean canCommit) { + this.commitSupported = canCommit; } + /* (non-Javadoc) + * @see com.gluster.storage.management.core.model.Entity#filter(java.lang.String, boolean) + */ + @Override + public boolean filter(String filterString, boolean caseSensitive) { + return StringUtil.filterString(getDescription() + getStatus().getMessage(), filterString, caseSensitive); + } } diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/TaskStatus.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/TaskStatus.java index 46dc7b31..c1205c0e 100644 --- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/TaskStatus.java +++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/TaskStatus.java @@ -22,7 +22,7 @@ package com.gluster.storage.management.core.model; public class TaskStatus extends Status { - private boolean isPercentageSupported; + private boolean isPercentageSupported = false; private float percentCompleted; private String description; diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/response/LogMessageListResponse.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/response/LogMessageListResponse.java index c1f879bb..8c362fa9 100644 --- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/response/LogMessageListResponse.java +++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/response/LogMessageListResponse.java @@ -9,11 +9,10 @@ import java.util.List; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; -import com.gluster.storage.management.core.model.Status; import com.gluster.storage.management.core.model.VolumeLogMessage; @XmlRootElement(name = "logMessages") -public class LogMessageListResponse extends AbstractResponse { +public class LogMessageListResponse { private List<VolumeLogMessage> logMessages = new ArrayList<VolumeLogMessage>(); public LogMessageListResponse() { @@ -23,11 +22,6 @@ public class LogMessageListResponse extends AbstractResponse { setLogMessages(logMessages); } - public LogMessageListResponse(Status status, List<VolumeLogMessage> logMessages) { - setStatus(status); - setLogMessages(logMessages); - } - @XmlElement(name = "logMessage", type = VolumeLogMessage.class) public List<VolumeLogMessage> getLogMessages() { return logMessages; @@ -36,9 +30,4 @@ public class LogMessageListResponse extends AbstractResponse { public void setLogMessages(List<VolumeLogMessage> logMessages) { this.logMessages = logMessages; } - - @Override - public Object getData() { - return getLogMessages(); - } } diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/response/ServerListResponse.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/response/ServerListResponse.java index 16059b15..05627ab1 100644 --- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/response/ServerListResponse.java +++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/response/ServerListResponse.java @@ -22,47 +22,27 @@ import java.util.ArrayList; import java.util.List; import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlElementWrapper; import javax.xml.bind.annotation.XmlRootElement; -import javax.xml.bind.annotation.XmlTransient; import com.gluster.storage.management.core.model.Server; -import com.gluster.storage.management.core.model.Status; -@XmlRootElement(name = "response") -public class ServerListResponse extends AbstractResponse { +@XmlRootElement(name = "servers") +public class ServerListResponse { private List<Server> servers = new ArrayList<Server>(); public ServerListResponse() { } - public ServerListResponse(Status status, List<Server> servers) { - setStatus(status); + public ServerListResponse(List<Server> servers) { setServers(servers); } - @XmlElementWrapper(name = "servers") @XmlElement(name = "server", type=Server.class) public List<Server> getServers() { return servers; } - /** - * @param servers - * the servers to set - */ public void setServers(List<Server> servers) { this.servers = servers; } - - /* - * (non-Javadoc) - * - * @see com.gluster.storage.management.core.model.Response#getData() - */ - @Override - @XmlTransient - public List<Server> getData() { - return getServers(); - } } diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/response/ServerNameListResponse.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/response/ServerNameListResponse.java new file mode 100644 index 00000000..2211f29f --- /dev/null +++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/response/ServerNameListResponse.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * 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.core.response; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * Response object for transferring cluster names during REST communication. This is just a wrapper over a list of + * Strings, and is required because the jersey rest framework can't transfer lists directly. + */ +@XmlRootElement(name="servers") +public class ServerNameListResponse { +private List<String> serverNames = new ArrayList<String>(); + + public ServerNameListResponse() { + } + + public ServerNameListResponse(List<String> serverNames) { + this.serverNames = serverNames; + } + + @XmlElement(name = "server", type = String.class) + public List<String> getServerNames() { + return serverNames; + } +} diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/response/TaskListResponse.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/response/TaskInfoListResponse.java index 2637b197..0ab27c35 100644 --- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/response/TaskListResponse.java +++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/response/TaskInfoListResponse.java @@ -20,35 +20,31 @@ */ package com.gluster.storage.management.core.response; -import java.util.ArrayList; import java.util.List; +import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; -import com.gluster.storage.management.core.model.Status; import com.gluster.storage.management.core.model.TaskInfo; -@XmlRootElement -public class TaskListResponse extends AbstractResponse { - private List<TaskInfo> taskList = new ArrayList<TaskInfo>(); - private Status status; - - public Status getStatus() { - return status; - } +@XmlRootElement(name = "tasks") +public class TaskInfoListResponse { + private List<TaskInfo> taskInfoList; - public void setStatus(Status status) { - this.status = status; - } + public TaskInfoListResponse() { + } - public void setData(List<TaskInfo> taskList) { - this.taskList.clear(); - this.taskList.addAll(taskList); + public TaskInfoListResponse(List<TaskInfo> taskInfoList) { + this.taskInfoList = taskInfoList; + } + + @XmlElement(name="task", type=TaskInfo.class) + public List<TaskInfo> getTaskList() { + return taskInfoList; } - @Override - public Object getData() { - return this.taskList; + public void setTaskList(List<TaskInfo> taskInfoList) { + this.taskInfoList = taskInfoList; } } diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/GlusterCoreUtil.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/GlusterCoreUtil.java index c238cad7..4194a642 100644 --- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/GlusterCoreUtil.java +++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/GlusterCoreUtil.java @@ -22,6 +22,7 @@ package com.gluster.storage.management.core.utils; import java.util.ArrayList; import java.util.List; +import java.util.Set; import com.gluster.storage.management.core.model.Brick; import com.gluster.storage.management.core.model.Disk; @@ -37,7 +38,7 @@ public class GlusterCoreUtil { return qualifiedDiskNames; } - public static final List<String> getQualifiedBrickList(List<Brick> bricks) { + public static final List<String> getQualifiedBrickList(Set<Brick> bricks) { List<String> qualifiedBricks = new ArrayList<String>(); for (Brick brick : bricks) { qualifiedBricks.add(brick.getQualifiedName()); diff --git a/src/com.gluster.storage.management.gui/icons/close_task.png b/src/com.gluster.storage.management.gui/icons/close_task.png Binary files differnew file mode 100644 index 00000000..933272b4 --- /dev/null +++ b/src/com.gluster.storage.management.gui/icons/close_task.png diff --git a/src/com.gluster.storage.management.gui/icons/pause_task.png b/src/com.gluster.storage.management.gui/icons/pause_task.png Binary files differnew file mode 100644 index 00000000..af57b25d --- /dev/null +++ b/src/com.gluster.storage.management.gui/icons/pause_task.png diff --git a/src/com.gluster.storage.management.gui/icons/star.png b/src/com.gluster.storage.management.gui/icons/star.png Binary files differnew file mode 100644 index 00000000..5f8fc748 --- /dev/null +++ b/src/com.gluster.storage.management.gui/icons/star.png diff --git a/src/com.gluster.storage.management.gui/icons/start_task.gif b/src/com.gluster.storage.management.gui/icons/start_task.gif Binary files differnew file mode 100644 index 00000000..2dfaef50 --- /dev/null +++ b/src/com.gluster.storage.management.gui/icons/start_task.gif diff --git a/src/com.gluster.storage.management.gui/icons/stop_task.png b/src/com.gluster.storage.management.gui/icons/stop_task.png Binary files differnew file mode 100644 index 00000000..7c6af7f0 --- /dev/null +++ b/src/com.gluster.storage.management.gui/icons/stop_task.png diff --git a/src/com.gluster.storage.management.gui/icons/tango/16x16/disk.png b/src/com.gluster.storage.management.gui/icons/tango/16x16/disk.png Binary files differnew file mode 100644 index 00000000..5c3b8587 --- /dev/null +++ b/src/com.gluster.storage.management.gui/icons/tango/16x16/disk.png diff --git a/src/com.gluster.storage.management.gui/icons/tango/16x16/help.png b/src/com.gluster.storage.management.gui/icons/tango/16x16/help.png Binary files differnew file mode 100644 index 00000000..f25fc3fb --- /dev/null +++ b/src/com.gluster.storage.management.gui/icons/tango/16x16/help.png diff --git a/src/com.gluster.storage.management.gui/icons/tango/16x16/logs.png b/src/com.gluster.storage.management.gui/icons/tango/16x16/logs.png Binary files differnew file mode 100644 index 00000000..8734e777 --- /dev/null +++ b/src/com.gluster.storage.management.gui/icons/tango/16x16/logs.png diff --git a/src/com.gluster.storage.management.gui/icons/tango/16x16/server.png b/src/com.gluster.storage.management.gui/icons/tango/16x16/server.png Binary files differnew file mode 100644 index 00000000..d0b397be --- /dev/null +++ b/src/com.gluster.storage.management.gui/icons/tango/16x16/server.png diff --git a/src/com.gluster.storage.management.gui/icons/tango/16x16/servers.png b/src/com.gluster.storage.management.gui/icons/tango/16x16/servers.png Binary files differnew file mode 100644 index 00000000..0efee57e --- /dev/null +++ b/src/com.gluster.storage.management.gui/icons/tango/16x16/servers.png diff --git a/src/com.gluster.storage.management.gui/icons/tango/16x16/settings.png b/src/com.gluster.storage.management.gui/icons/tango/16x16/settings.png Binary files differnew file mode 100644 index 00000000..d90ab661 --- /dev/null +++ b/src/com.gluster.storage.management.gui/icons/tango/16x16/settings.png diff --git a/src/com.gluster.storage.management.gui/icons/tango/16x16/volume-create.png b/src/com.gluster.storage.management.gui/icons/tango/16x16/volume-create.png Binary files differnew file mode 100644 index 00000000..628f4d50 --- /dev/null +++ b/src/com.gluster.storage.management.gui/icons/tango/16x16/volume-create.png diff --git a/src/com.gluster.storage.management.gui/icons/tango/16x16/volume.png b/src/com.gluster.storage.management.gui/icons/tango/16x16/volume.png Binary files differnew file mode 100644 index 00000000..5234eab4 --- /dev/null +++ b/src/com.gluster.storage.management.gui/icons/tango/16x16/volume.png diff --git a/src/com.gluster.storage.management.gui/icons/tango/32x32/disk.png b/src/com.gluster.storage.management.gui/icons/tango/32x32/disk.png Binary files differnew file mode 100644 index 00000000..b34d8b77 --- /dev/null +++ b/src/com.gluster.storage.management.gui/icons/tango/32x32/disk.png diff --git a/src/com.gluster.storage.management.gui/icons/tango/32x32/help.png b/src/com.gluster.storage.management.gui/icons/tango/32x32/help.png Binary files differnew file mode 100644 index 00000000..d60425f7 --- /dev/null +++ b/src/com.gluster.storage.management.gui/icons/tango/32x32/help.png diff --git a/src/com.gluster.storage.management.gui/icons/tango/32x32/logs.png b/src/com.gluster.storage.management.gui/icons/tango/32x32/logs.png Binary files differnew file mode 100644 index 00000000..b62959e4 --- /dev/null +++ b/src/com.gluster.storage.management.gui/icons/tango/32x32/logs.png diff --git a/src/com.gluster.storage.management.gui/icons/tango/32x32/server.png b/src/com.gluster.storage.management.gui/icons/tango/32x32/server.png Binary files differnew file mode 100644 index 00000000..e34eb4e4 --- /dev/null +++ b/src/com.gluster.storage.management.gui/icons/tango/32x32/server.png diff --git a/src/com.gluster.storage.management.gui/icons/tango/32x32/servers.png b/src/com.gluster.storage.management.gui/icons/tango/32x32/servers.png Binary files differnew file mode 100644 index 00000000..dca03af4 --- /dev/null +++ b/src/com.gluster.storage.management.gui/icons/tango/32x32/servers.png diff --git a/src/com.gluster.storage.management.gui/icons/tango/32x32/settings.png b/src/com.gluster.storage.management.gui/icons/tango/32x32/settings.png Binary files differnew file mode 100644 index 00000000..565f406d --- /dev/null +++ b/src/com.gluster.storage.management.gui/icons/tango/32x32/settings.png diff --git a/src/com.gluster.storage.management.gui/icons/tango/32x32/volume-create.png b/src/com.gluster.storage.management.gui/icons/tango/32x32/volume-create.png Binary files differnew file mode 100644 index 00000000..fcd15c01 --- /dev/null +++ b/src/com.gluster.storage.management.gui/icons/tango/32x32/volume-create.png diff --git a/src/com.gluster.storage.management.gui/icons/tango/32x32/volume.png b/src/com.gluster.storage.management.gui/icons/tango/32x32/volume.png Binary files differnew file mode 100644 index 00000000..3e0d9add --- /dev/null +++ b/src/com.gluster.storage.management.gui/icons/tango/32x32/volume.png diff --git a/src/com.gluster.storage.management.gui/icons/tango/48x48/server.png b/src/com.gluster.storage.management.gui/icons/tango/48x48/server.png Binary files differnew file mode 100644 index 00000000..a568c0b8 --- /dev/null +++ b/src/com.gluster.storage.management.gui/icons/tango/48x48/server.png diff --git a/src/com.gluster.storage.management.gui/icons/tango/48x48/volume-create.png b/src/com.gluster.storage.management.gui/icons/tango/48x48/volume-create.png Binary files differnew file mode 100644 index 00000000..967d1844 --- /dev/null +++ b/src/com.gluster.storage.management.gui/icons/tango/48x48/volume-create.png diff --git a/src/com.gluster.storage.management.gui/icons/tango/48x48/volume.png b/src/com.gluster.storage.management.gui/icons/tango/48x48/volume.png Binary files differnew file mode 100644 index 00000000..4bd1a2aa --- /dev/null +++ b/src/com.gluster.storage.management.gui/icons/tango/48x48/volume.png diff --git a/src/com.gluster.storage.management.gui/plugin.xml b/src/com.gluster.storage.management.gui/plugin.xml index af065b7d..112c8e81 100644 --- a/src/com.gluster.storage.management.gui/plugin.xml +++ b/src/com.gluster.storage.management.gui/plugin.xml @@ -30,14 +30,6 @@ restorable="true"> </view> <view - category="org.eclipse.ui" - class="org.eclipse.ui.ExtensionFactory:progressView" - icon="icons/progress-bar.png" - id="org.eclipse.ui.views.ProgressView" - name="Tasks in Progress" - restorable="true"> - </view> - <view allowMultiple="false" category="com.gluster.storage.management.gui.category" class="com.gluster.storage.management.gui.views.DiscoveredServersView" @@ -62,7 +54,7 @@ allowMultiple="false" category="com.gluster.storage.management.gui.category" class="com.gluster.storage.management.gui.views.VolumesView" - icon="icons/volumes.png" + icon="icons/tango/16x16/volume.png" id="com.gluster.storage.management.gui.views.VolumesView" name="Volumes" restorable="true"> @@ -107,7 +99,7 @@ allowMultiple="false" category="com.gluster.storage.management.gui.category" class="com.gluster.storage.management.gui.views.VolumeOptionsView" - icon="icons/preferences.png" + icon="icons/tango/16x16/settings.png" id="com.gluster.storage.management.gui.views.VolumeOptionsView" name="Volume Options" restorable="true"> @@ -116,7 +108,7 @@ allowMultiple="false" category="com.gluster.storage.management.gui.category" class="com.gluster.storage.management.gui.views.VolumeLogsView" - icon="icons/logs.png" + icon="icons/tango/16x16/logs.png" id="com.gluster.storage.management.gui.views.VolumeLogsView" name="Volume Logs" restorable="true"> @@ -134,7 +126,7 @@ allowMultiple="false" category="com.gluster.storage.management.gui.category" class="com.gluster.storage.management.gui.views.GlusterServersView" - icon="icons/servers.png" + icon="icons/tango/16x16/servers.png" id="com.gluster.storage.management.gui.views.GlusterServersView" name="Servers" restorable="true"> @@ -143,7 +135,7 @@ allowMultiple="false" category="com.gluster.storage.management.gui.category" class="com.gluster.storage.management.gui.views.DisksView" - icon="icons/disks.png" + icon="icons/tango/16x16/disk.png" id="com.gluster.storage.management.gui.views.DisksView" name="Disks" restorable="true"> @@ -161,7 +153,7 @@ allowMultiple="false" category="com.gluster.storage.management.gui.category" class="com.gluster.storage.management.gui.views.GlusterServerDisksView" - icon="icons/disks.png" + icon="icons/tango/16x16/disk.png" id="com.gluster.storage.management.gui.views.GlusterServerDisksView" name="Server Disks" restorable="true"> @@ -170,11 +162,20 @@ allowMultiple="false" category="com.gluster.storage.management.gui.category" class="com.gluster.storage.management.gui.views.GlusterServerLogsView" - icon="icons/logs.png" + icon="icons/tango/16x16/logs.png" id="com.gluster.storage.management.gui.views.GlusterServerLogsView" name="Server Logs" restorable="true"> </view> + <view + allowMultiple="false" + category="com.gluster.storage.management.gui.category" + class="com.gluster.storage.management.gui.views.TasksView" + icon="icons/progress-bar.png" + id="com.gluster.storage.management.gui.views.TasksView" + name="Tasks" + restorable="true"> + </view> </extension> <extension point="org.eclipse.ui.commands"> @@ -249,10 +250,35 @@ name="Remove Brick"> </command> <command + categoryId="com.gluster.storage.management.gui.category" description="Add Brick" id="com.gluster.storage.management.gui.commands.AddDisk" name="Add Brick"> </command> + <command + categoryId="com.gluster.storage.management.gui.category" + description="Pause Task" + id="com.gluster.storage.management.gui.commands.Pause" + name="Pause"> + </command> + <command + categoryId="com.gluster.storage.management.gui.category" + description="Resume Task" + id="com.gluster.storage.management.gui.commands.Resume" + name="Resume"> + </command> + <command + categoryId="com.gluster.storage.management.gui.category" + description="Stop Task" + id="com.gluster.storage.management.gui.commands.Stop" + name="Stop"> + </command> + <command + categoryId="com.gluster.storage.management.gui.category" + description="Delete Task" + id="com.gluster.storage.management.gui.commands.Delete" + name="Delete"> + </command> </extension> <extension point="org.eclipse.ui.bindings"> @@ -374,7 +400,7 @@ allowLabelUpdate="false" class="com.gluster.storage.management.gui.actions.PreferencesAction" definitionId="org.eclipse.ui.window.preferences" - icon="icons/preferences.png" + icon="icons/tango/32x32/settings.png" id="com.gluster.storage.management.gui.actions.AddServerAction" label="&Settings" menubarPath="com.gluster.storage.management.gui.menu.edit/edit" @@ -519,7 +545,7 @@ allowLabelUpdate="false" class="com.gluster.storage.management.gui.actions.DownloadVolumeLogsAction" definitionId="com.gluster.storage.management.gui.commands.DownloadVolumeLogs" - icon="icons/logs.png" + icon="icons/tango/16x16/logs.png" id="com.gluster.storage.management.gui.actions.DownloadVolumeLogsAction" label="Download &Logs" menubarPath="com.gluster.storage.management.gui.menu.volume/volume" @@ -535,7 +561,7 @@ allowLabelUpdate="false" class="com.gluster.storage.management.gui.actions.ResetVolumeOptionsAction" definitionId="com.gluster.storage.management.gui.commands.ResetVolumeOptions" - icon="icons/reset-options.png" + icon="icons/tango/16x16/settings.png" id="com.gluster.storage.management.gui.actions.ResetVolumeOptionsAction" label="Reset &Options" menubarPath="com.gluster.storage.management.gui.menu.volume/volume" @@ -643,9 +669,89 @@ visible="false"> <action allowLabelUpdate="false" + class="com.gluster.storage.management.gui.actions.ClearTaskAction" + definitionId="com.gluster.storage.management.gui.commands.Clear" + icon="icons/close_task.png" + id="com.gluster.storage.management.gui.actions.Clear" + label="&Clear Task" + menubarPath="com.gluster.storage.management.gui.menu.cluster/cluster" + mode="FORCE_TEXT" + pulldown="false" + retarget="false" + state="false" + style="push" + toolbarPath="Normal" + tooltip="To clear selected task from task list"> + </action> + <action + allowLabelUpdate="false" + class="com.gluster.storage.management.gui.actions.CommitTaskAction" + definitionId="com.gluster.storage.management.gui.commands.Commit" + icon="icons/stop.png" + id="com.gluster.storage.management.gui.actions.Commit" + label="&Commit TaskTask" + menubarPath="com.gluster.storage.management.gui.menu.cluster/cluster" + mode="FORCE_TEXT" + pulldown="false" + retarget="false" + state="false" + style="push" + toolbarPath="Normal" + tooltip="To Commit the selected task"> + </action> + <action + allowLabelUpdate="false" + class="com.gluster.storage.management.gui.actions.StopTaskAction" + definitionId="com.gluster.storage.management.gui.commands.Stop" + icon="icons/stop_task.png" + id="com.gluster.storage.management.gui.actions.Stop" + label="&Stop Task" + menubarPath="com.gluster.storage.management.gui.menu.cluster/cluster" + mode="FORCE_TEXT" + pulldown="false" + retarget="false" + state="false" + style="push" + toolbarPath="Normal" + tooltip="To Stop the selected task"> + </action> + <action + allowLabelUpdate="false" + class="com.gluster.storage.management.gui.actions.ResumeTaskAction" + definitionId="com.gluster.storage.management.gui.commands.Pause" + icon="icons/start_task.gif" + id="com.gluster.storage.management.gui.actions.Resume" + label="&Resume Task" + menubarPath="com.gluster.storage.management.gui.menu.cluster/cluster" + mode="FORCE_TEXT" + pulldown="false" + retarget="false" + state="false" + style="push" + toolbarPath="Normal" + tooltip="To Resume the selected task"> + </action> + <action + allowLabelUpdate="false" + class="com.gluster.storage.management.gui.actions.PauseTaskAction" + definitionId="com.gluster.storage.management.gui.commands.Pause" + icon="icons/pause_task.png" + id="com.gluster.storage.management.gui.actions.Pause" + label="&Pause Task" + menubarPath="com.gluster.storage.management.gui.menu.cluster/cluster" + mode="FORCE_TEXT" + pulldown="false" + retarget="false" + state="false" + style="push" + toolbarPath="Normal" + tooltip="To Pause the selected task"> + </action> + <action + allowLabelUpdate="false" class="com.gluster.storage.management.gui.actions.CreateVolumeAction" definitionId="com.gluster.storage.management.gui.commands.CreateVolume" - icon="icons/volume-create.png" + icon="icons/tango/32x32/volume-create.png" id="com.gluster.storage.management.gui.actions.CreateVolumeAction" label="Create &Volume" menubarPath="com.gluster.storage.management.gui.menu.cluster/cluster" @@ -1006,6 +1112,18 @@ standalone="false" visible="false"> </view> + <view + closeable="false" + id="com.gluster.storage.management.gui.views.TasksView" + minimized="false" + moveable="false" + ratio="0.30f" + relationship="stack" + relative="com.gluster.storage.management.gui.views.ClusterSummaryView" + showTitle="true" + standalone="false" + visible="false"> + </view> </perspectiveExtension> </extension> <extension diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/Application.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/Application.java index 0e269c3a..598f9639 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/Application.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/Application.java @@ -73,6 +73,8 @@ public class Application implements IApplication { * @see org.eclipse.equinox.app.IApplication#start(org.eclipse.equinox.app.IApplicationContext) */ public Object start(IApplicationContext context) { + setSystemProperties(); + Display display = PlatformUI.createDisplay(); final boolean[] loginSuccess = new boolean[1]; @@ -96,6 +98,12 @@ public class Application implements IApplication { } } + private void setSystemProperties() { + // TODO: Trying this to avoid the webstart authentication dialog + // to be tested, and removed if this doesn't work. + System.setProperty("javaws.cfg.jauthenticator", "none"); + } + /* * (non-Javadoc) * diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/IImageKeys.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/IImageKeys.java index 65124bf9..5836f6f9 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/IImageKeys.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/IImageKeys.java @@ -20,10 +20,10 @@ package com.gluster.storage.management.gui; public interface IImageKeys { public static final String CLUSTER = "icons/cluster.png"; - public static final String VOLUMES = "icons/volumes.png"; - public static final String SERVERS = "icons/servers.png"; - public static final String VOLUME = "icons/volume.png"; - public static final String SERVER = "icons/server.png"; + public static final String VOLUMES = "icons/tango/16x16/volume.png"; + public static final String SERVERS = "icons/tango/16x16/servers.png"; + public static final String VOLUME = "icons/tango/16x16/volume.png"; + public static final String SERVER = "icons/tango/16x16/server.png"; public static final String SERVER_WARNING = "icons/server-warning.png"; public static final String MEMORY = "icons/memory.png"; public static final String GSN = "icons/gsn.png"; @@ -31,10 +31,10 @@ public interface IImageKeys { public static final String ADD = "icons/plus-white.png"; public static final String REMOVE = "icons/minus-white.png"; public static final String CREATE_VOLUME = "icons/volume-create.png"; - public static final String CREATE_VOLUME_BIG = "icons/volume-create-big.png"; + public static final String CREATE_VOLUME_BIG = "icons/tango/48x48/volume-create.png"; public static final String REMOVE_VOLUME = "icons/volume-delete.png"; public static final String ADD_SERVER = "icons/server-add.png"; - public static final String ADD_SERVER_BIG = "icons/server-add-big.png"; + public static final String ADD_SERVER_BIG = "icons/tango/48x48/server.png"; public static final String REMOVE_SERVER = "icons/server-remove.png"; public static final String HELP = "icons/question.png"; public static final String STATUS_OFFLINE = "icons/status-offline.png"; @@ -44,8 +44,8 @@ public interface IImageKeys { public static final String WORK_IN_PROGRESS = "icons/progress-bar.png"; public static final String CHECKBOX_UNCHECKED = "icons/ui-check-box-uncheck.png"; public static final String CHECKBOX_CHECKED = "icons/ui-check-box.png"; - public static final String DISK = "icons/disk.png"; - public static final String DISKS = "icons/disks.png"; + public static final String DISK = "icons/tango/16x16/disk.png"; + public static final String DISKS = "icons/tango/16x16/disk.png"; public static final String DISK_UNINITIALIZED = "icons/disk-uninitialized.png"; public static final String SEARCH = "icons/search.png"; public static final String ARROW_UP = "icons/arrow-up.png"; @@ -55,9 +55,14 @@ public interface IImageKeys { public static final String LOW_DISK_SPACE = "icons/disk.png"; public static final String DISK_OFFLINE = "icons/status-offline.png"; + public static final String PAUSE_TASK = "icons/pause_task.gif"; + public static final String RESUME_TASK = "icons/resume_task.gif"; + public static final String STOP_TASK = "icons/stop_task.gif"; + public static final String CLEAR_TASK = "icons/close_task.gif"; + public static final String OVERLAY_OFFLINE = "icons/status-offline-small.png"; public static final String OVERLAY_ONLINE = "icons/status-online-small.png"; - public static final String OVERLAY_STAR = "icons/star-small.png"; + public static final String OVERLAY_STAR = "icons/star.png"; public static final String SPLASH_IMAGE = "splash.bmp"; public static final String DIALOG_SPLASH_IMAGE = "splash/splash-dialog.bmp"; diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/TasksTableLabelProvider.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/TasksTableLabelProvider.java new file mode 100644 index 00000000..82aa1f44 --- /dev/null +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/TasksTableLabelProvider.java @@ -0,0 +1,45 @@ +/** + * TasksTableLabelProvider.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.gui; + +import org.eclipse.swt.graphics.Image; + +import com.gluster.storage.management.core.model.TaskInfo; +import com.gluster.storage.management.gui.views.pages.TasksPage.TASK_TABLE_COLUMN_INDICES; + + +public class TasksTableLabelProvider extends TableLabelProviderAdapter { + + @Override + public Image getColumnImage(Object element, int columnIndex) { + return null; + } + + @Override + public String getColumnText(Object element, int columnIndex) { + if (!(element instanceof TaskInfo)) { + return null; + } + + TaskInfo taskInfo = (TaskInfo) element; + return (columnIndex == TASK_TABLE_COLUMN_INDICES.TASK.ordinal()) ? taskInfo.getDescription().trim() : taskInfo.getStatus().getMessage().trim(); + } +} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/ClearTaskAction.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/ClearTaskAction.java new file mode 100644 index 00000000..f1eb8a94 --- /dev/null +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/ClearTaskAction.java @@ -0,0 +1,53 @@ +package com.gluster.storage.management.gui.actions; + +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.widgets.Display; + +import com.gluster.storage.management.client.GlusterDataModelManager; +import com.gluster.storage.management.client.TasksClient; +import com.gluster.storage.management.core.model.Status; +import com.gluster.storage.management.core.model.TaskInfo; + +public class ClearTaskAction extends AbstractActionDelegate { + private TaskInfo taskInfo; + private GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance(); + + @Override + protected void performAction(final IAction action) { + Display.getDefault().asyncExec(new Runnable() { + + @Override + public void run() { + final String actionDesc = action.getDescription(); + + try { + new TasksClient().resumeTask(taskInfo.getName()); + // TODO Update taskInfo in the model + // modelManager.updateVolumeStatus(volume, VOLUME_STATUS.OFFLINE); + modelManager.removeTask(taskInfo); + } catch (Exception e) { + showErrorDialog(actionDesc, + "Task [" + taskInfo.getName() + "] could not be cleared! Error: [" + e.getMessage() + "]"); + } + } + }); + } + + @Override + public void selectionChanged(IAction action, ISelection selection) { + super.selectionChanged(action, selection); + action.setEnabled(false); + if (selectedEntity instanceof TaskInfo) { + taskInfo = (TaskInfo) selectedEntity; + action.setEnabled(taskInfo.getStatus().getCode() == Status.STATUS_CODE_SUCCESS + || taskInfo.getStatus().getCode() == Status.STATUS_CODE_FAILURE); + } + } + + @Override + public void dispose() { + + } + +} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/CommitTaskAction.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/CommitTaskAction.java new file mode 100644 index 00000000..9655b2b3 --- /dev/null +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/CommitTaskAction.java @@ -0,0 +1,54 @@ +package com.gluster.storage.management.gui.actions; + +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.widgets.Display; + +import com.gluster.storage.management.client.GlusterDataModelManager; +import com.gluster.storage.management.client.TasksClient; +import com.gluster.storage.management.core.model.Status; +import com.gluster.storage.management.core.model.TaskInfo; +import com.gluster.storage.management.core.model.TaskStatus; + +public class CommitTaskAction extends AbstractActionDelegate { + private TaskInfo taskInfo; + private GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance(); + + @Override + protected void performAction(final IAction action) { + Display.getDefault().asyncExec(new Runnable() { + + @Override + public void run() { + final String actionDesc = action.getDescription(); + + try { + new TasksClient().commitTask(taskInfo.getName()); + taskInfo.setStatus(new TaskStatus(new Status(Status.STATUS_CODE_SUCCESS, taskInfo.getName() + + " is commited"))); + modelManager.updateTask(taskInfo); + } catch (Exception e) { + showErrorDialog(actionDesc, + "Task [" + taskInfo.getName() + "] could not be Stopped! Error: [" + e.getMessage() + "]"); + } + } + }); + } + + @Override + public void selectionChanged(IAction action, ISelection selection) { + super.selectionChanged(action, selection); + action.setEnabled(false); + if (selectedEntity instanceof TaskInfo) { + taskInfo = (TaskInfo) selectedEntity; + action.setEnabled(taskInfo.canCommit() + && taskInfo.getStatus().getCode() == Status.STATUS_CODE_COMMIT_PENDING); + } + } + + @Override + public void dispose() { + + } + +} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/MigrateDiskAction.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/MigrateDiskAction.java index bbb29253..56ea8179 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/MigrateDiskAction.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/MigrateDiskAction.java @@ -18,14 +18,16 @@ *******************************************************************************/ package com.gluster.storage.management.gui.actions; +import java.util.Set; + import org.eclipse.jface.action.IAction; import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.wizard.WizardDialog; import com.gluster.storage.management.core.model.Brick; import com.gluster.storage.management.core.model.Volume; import com.gluster.storage.management.gui.dialogs.MigrateDiskWizard; +import com.gluster.storage.management.gui.utils.GUIHelper; public class MigrateDiskAction extends AbstractActionDelegate { private Volume volume; @@ -33,9 +35,6 @@ public class MigrateDiskAction extends AbstractActionDelegate { @Override protected void performAction(IAction action) { -// MigrateDiskDialog dialog = new MigrateDiskDialog(window.getShell(), volume, disk); -// dialog.create(); -// dialog.open(); MigrateDiskWizard wizard = new MigrateDiskWizard(volume, brick); WizardDialog dialog = new WizardDialog(window.getShell(), wizard); @@ -47,15 +46,16 @@ public class MigrateDiskAction extends AbstractActionDelegate { @Override public void selectionChanged(IAction action, ISelection selection) { super.selectionChanged(action, selection); - + Set<Brick> bricks; if (selectedEntity instanceof Volume) { volume = (Volume) selectedEntity; } action.setEnabled(false); if (selectedEntity instanceof Brick) { - brick = (Brick) selectedEntity; - action.setEnabled(((StructuredSelection) selection).size() == 1); + bricks = GUIHelper.getInstance().getSelectedEntities(getWindow(), Brick.class); + brick = (Brick) bricks.iterator().next(); + action.setEnabled(brick != null); } } diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/PauseTaskAction.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/PauseTaskAction.java new file mode 100644 index 00000000..b36b7855 --- /dev/null +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/PauseTaskAction.java @@ -0,0 +1,76 @@ +/** + * PauseTaskAction.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.gui.actions; + +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.widgets.Display; + +import com.gluster.storage.management.client.GlusterDataModelManager; +import com.gluster.storage.management.client.TasksClient; +import com.gluster.storage.management.core.model.Status; +import com.gluster.storage.management.core.model.TaskInfo; +import com.gluster.storage.management.core.model.TaskStatus; + + +public class PauseTaskAction extends AbstractActionDelegate { + private TaskInfo taskInfo; + private GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance(); + + @Override + protected void performAction(final IAction action) { + Display.getDefault().asyncExec(new Runnable() { + + @Override + public void run() { + final String actionDesc = action.getDescription(); + + try { + new TasksClient().pauseTask(taskInfo.getName()); + taskInfo.setStatus(new TaskStatus(new Status(Status.STATUS_CODE_PAUSE, taskInfo.getName() + + " is Paused"))); + modelManager.updateTask(taskInfo); + } catch (Exception e) { + showErrorDialog(actionDesc, + "Task [" + taskInfo.getName() + "] could not be Paused! Error: [" + e.getMessage() + "]"); + } + } + }); + } + + + @Override + public void selectionChanged(IAction action, ISelection selection) { + super.selectionChanged(action, selection); + action.setEnabled(false); + if (selectedEntity instanceof TaskInfo) { + taskInfo = (TaskInfo) selectedEntity; + action.setEnabled(taskInfo.canPause() && taskInfo.getStatus().getCode() == Status.STATUS_CODE_RUNNING); + } + } + + @Override + public void dispose() { + // TODO Auto-generated method stub + + } + +} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/RebalanceVolumeAction.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/RebalanceVolumeAction.java index 5339beb0..33ca0e5b 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/RebalanceVolumeAction.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/RebalanceVolumeAction.java @@ -19,11 +19,44 @@ package com.gluster.storage.management.gui.actions; import org.eclipse.jface.action.IAction; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.widgets.Display; + +import com.gluster.storage.management.client.VolumesClient; +import com.gluster.storage.management.core.model.Volume; public class RebalanceVolumeAction extends AbstractActionDelegate { + private Volume volume; + + @Override + protected void performAction(final IAction action) { + + Display.getDefault().asyncExec(new Runnable() { + + @Override + public void run() { + final String actionDesc = action.getDescription(); + try { + new VolumesClient().rebalanceStart(volume.getName(), false, false, false); + showInfoDialog(actionDesc, "Volume [" + volume.getName() + "] rebalance started successfully!"); + } catch (Exception e) { + showErrorDialog(actionDesc, + "Volume rebalance could not be started on [" + volume.getName() + "]! Error: [" + e.getMessage() + "]"); + } + + } + }); + } + @Override - protected void performAction(IAction action) { - System.out.println("Running [" + this.getClass().getSimpleName() + "]"); + public void selectionChanged(IAction action, ISelection selection) { + super.selectionChanged(action, selection); + + action.setEnabled(false); + if (selectedEntity instanceof Volume) { + volume = (Volume) selectedEntity; + action.setEnabled(true); + } } @Override diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/RemoveDiskAction.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/RemoveDiskAction.java index 9df40457..b79a4ee4 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/RemoveDiskAction.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/RemoveDiskAction.java @@ -3,6 +3,7 @@ package com.gluster.storage.management.gui.actions; import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.Set; import org.eclipse.jface.action.IAction; import org.eclipse.jface.dialogs.MessageDialog; @@ -15,6 +16,7 @@ import org.eclipse.ui.IWorkbenchPart; import com.gluster.storage.management.client.GlusterDataModelManager; import com.gluster.storage.management.client.VolumesClient; import com.gluster.storage.management.core.model.Brick; +import com.gluster.storage.management.core.model.GlusterServer; import com.gluster.storage.management.core.model.Status; import com.gluster.storage.management.core.model.Volume; import com.gluster.storage.management.core.utils.StringUtil; @@ -25,7 +27,7 @@ import com.gluster.storage.management.gui.views.VolumeBricksView; public class RemoveDiskAction extends AbstractActionDelegate { private GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance(); private GUIHelper guiHelper = GUIHelper.getInstance(); - private List<Brick> bricks; + private Set<Brick> bricks; private Volume volume; boolean confirmDelete = false; @@ -90,28 +92,13 @@ public class RemoveDiskAction extends AbstractActionDelegate { IWorkbenchPart view = guiHelper.getActiveView(); if (view instanceof VolumeBricksView) { // volume disks view is open. check if any brick is selected - bricks = getSelectedBricks(selection); + bricks = GUIHelper.getInstance().getSelectedEntities(getWindow(), Brick.class); action.setEnabled(bricks.size() > 0); } } } - private List<Brick> getSelectedBricks(ISelection selection) { - List<Brick> selectedBricks = new ArrayList<Brick>(); - - if (selection instanceof IStructuredSelection) { - Iterator<Object> iter = ((IStructuredSelection) selection).iterator(); - while (iter.hasNext()) { - Object selectedObj = iter.next(); - if (selectedObj instanceof Brick) { - selectedBricks.add((Brick) selectedObj); - } - } - } - return selectedBricks; - } - - private List<String> getBrickList(List<Brick> bricks) { + private List<String> getBrickList(Set<Brick> bricks) { List<String> brickList = new ArrayList<String>(); for (Brick brick : bricks) { brickList.add(brick.getServerName() + ":" + brick.getBrickDirectory()); diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/ResumeTaskAction.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/ResumeTaskAction.java new file mode 100644 index 00000000..fc80b04d --- /dev/null +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/ResumeTaskAction.java @@ -0,0 +1,55 @@ +package com.gluster.storage.management.gui.actions; + +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.widgets.Display; + +import com.gluster.storage.management.client.GlusterDataModelManager; +import com.gluster.storage.management.client.TasksClient; +import com.gluster.storage.management.core.model.Status; +import com.gluster.storage.management.core.model.TaskInfo; +import com.gluster.storage.management.core.model.TaskStatus; + +public class ResumeTaskAction extends AbstractActionDelegate { + private TaskInfo taskInfo; + private GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance(); + + @Override + protected void performAction(final IAction action) { + Display.getDefault().asyncExec(new Runnable() { + + @Override + public void run() { + final String actionDesc = action.getDescription(); + + try { + new TasksClient().resumeTask(taskInfo.getName()); + taskInfo.setStatus(new TaskStatus(new Status(Status.STATUS_CODE_RUNNING, taskInfo.getName() + + " is Resumed"))); + modelManager.updateTask(taskInfo); + } catch (Exception e) { + showErrorDialog(actionDesc, + "Task [" + taskInfo.getName() + "] could not be Resumed! Error: [" + e.getMessage() + "]"); + } + } + }); + } + + @Override + public void selectionChanged(IAction action, ISelection selection) { + super.selectionChanged(action, selection); + action.setEnabled(false); + if (selectedEntity instanceof TaskInfo) { + taskInfo = (TaskInfo) selectedEntity; + action.setEnabled(taskInfo.getStatus().getCode() == Status.STATUS_CODE_PAUSE); + } + } + + @Override + public void dispose() { + + + } + + +} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/StopTaskAction.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/StopTaskAction.java new file mode 100644 index 00000000..abde4e57 --- /dev/null +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/StopTaskAction.java @@ -0,0 +1,54 @@ +package com.gluster.storage.management.gui.actions; + +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.widgets.Display; + +import com.gluster.storage.management.client.GlusterDataModelManager; +import com.gluster.storage.management.client.TasksClient; +import com.gluster.storage.management.core.model.Status; +import com.gluster.storage.management.core.model.TaskInfo; +import com.gluster.storage.management.core.model.TaskStatus; + +public class StopTaskAction extends AbstractActionDelegate { + private TaskInfo taskInfo; + private GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance(); + + @Override + protected void performAction(final IAction action) { + Display.getDefault().asyncExec(new Runnable() { + + @Override + public void run() { + final String actionDesc = action.getDescription(); + + try { + new TasksClient().resumeTask(taskInfo.getName()); + taskInfo.setStatus( new TaskStatus( new Status(Status.STATUS_CODE_SUCCESS, taskInfo.getName() + " is Stopped"))); + modelManager.updateTask(taskInfo); + } catch (Exception e) { + showErrorDialog(actionDesc, + "Task [" + taskInfo.getName() + "] could not be Stopped! Error: [" + e.getMessage() + "]"); + } + } + }); + } + + @Override + public void selectionChanged(IAction action, ISelection selection) { + super.selectionChanged(action, selection); + action.setEnabled(false); + if (selectedEntity instanceof TaskInfo) { + taskInfo = (TaskInfo) selectedEntity; + action.setEnabled(taskInfo.canStop() + && (taskInfo.getStatus().getCode() == Status.STATUS_CODE_PAUSE + || taskInfo.getStatus().getCode() == Status.STATUS_CODE_RUNNING)); + } + } + + @Override + public void dispose() { + + } + +} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/ClusterSelectionDialog.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/ClusterSelectionDialog.java index 342c72e6..82df0c46 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/ClusterSelectionDialog.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/ClusterSelectionDialog.java @@ -20,9 +20,12 @@ package com.gluster.storage.management.gui.dialogs; import java.util.List; +import org.eclipse.core.runtime.preferences.ConfigurationScope; +import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.fieldassist.ControlDecoration; +import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StackLayout; import org.eclipse.swt.events.ModifyEvent; @@ -40,8 +43,14 @@ import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; +import org.osgi.service.prefs.BackingStoreException; +import com.gluster.storage.management.core.constants.CoreConstants; +import com.gluster.storage.management.core.exceptions.GlusterRuntimeException; +import com.gluster.storage.management.gui.Activator; +import com.gluster.storage.management.gui.Application; import com.gluster.storage.management.gui.IImageKeys; +import com.gluster.storage.management.gui.preferences.PreferenceConstants; import com.gluster.storage.management.gui.utils.GUIHelper; /** @@ -73,10 +82,13 @@ public class ClusterSelectionDialog extends Dialog { private String clusterName; private CLUSTER_MODE clusterMode; private String serverName; + private Button dontAskAgainButton; + IPreferenceStore preferenceStore; public ClusterSelectionDialog(Shell parentShell, List<String> clusters) { super(parentShell); this.clusters = clusters; + preferenceStore = Activator.getDefault().getPreferenceStore(); } @Override @@ -109,6 +121,20 @@ public class ClusterSelectionDialog extends Dialog { clusterNameCombo = new Combo(composite, SWT.READ_ONLY); clusterNameCombo.setItems(clusters.toArray(new String[0])); clusterNameCombo.select(0); + + String clusterName = preferenceStore.getString(PreferenceConstants.P_DEFAULT_CLUSTER_NAME); + if(clusterName != null && !clusterName.isEmpty()) { + selectCluster(clusterName); + } + } + + public void selectCluster(String clusterName) { + for(int i = 0; i < clusters.size(); i++) { + if(clusterNameCombo.getItem(i).equals(clusterName)) { + clusterNameCombo.select(i); + break; + } + } } private void configureDialogLayout(Composite composite) { @@ -231,9 +257,26 @@ public class ClusterSelectionDialog extends Dialog { clusterSelectionComposite.setLayout(layout); createClusterNameLabel(clusterSelectionComposite); createClusterNameCombo(clusterSelectionComposite); + + createPreferenceCheckboxes(clusterSelectionComposite); + stackLayout.topControl = clusterSelectionComposite; } + private void createPreferenceCheckboxes(Composite composite) { + GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, false); + layoutData.verticalIndent = 5; + layoutData.horizontalSpan = 2; + + dontAskAgainButton = new Button(composite, SWT.CHECK); + dontAskAgainButton.setLayoutData(layoutData); + dontAskAgainButton.setText("&Don't ask again"); + dontAskAgainButton.setEnabled(true); + dontAskAgainButton.setSelection(false); + dontAskAgainButton.setToolTipText("Always manage the selected cluster without showing this dialog box." + + "This preference can later be changed from the \"Settings\" menu."); + } + private void createRadioButtons() { { if (clusters.size() > 0) { @@ -371,6 +414,13 @@ public class ClusterSelectionDialog extends Dialog { if(selectButton != null && selectButton.getSelection()) { clusterMode = CLUSTER_MODE.SELECT; clusterName = clusterNameCombo.getText(); + + if(dontAskAgainButton.getSelection()) { + preferenceStore.setValue(PreferenceConstants.P_SHOW_CLUSTER_SELECTION_DIALOG, false); + preferenceStore.setValue(PreferenceConstants.P_DEFAULT_CLUSTER_NAME, clusterName); + } else { + preferenceStore.setValue(PreferenceConstants.P_SHOW_CLUSTER_SELECTION_DIALOG, true); + } } else if(createButton.getSelection()) { clusterMode = CLUSTER_MODE.CREATE; clusterName = newClusterNameText.getText().trim(); diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/LoginDialog.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/LoginDialog.java index 563e6416..487a03c4 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/LoginDialog.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/LoginDialog.java @@ -28,6 +28,7 @@ import org.eclipse.jface.databinding.swt.WidgetProperties; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.window.Window; import org.eclipse.swt.SWT; import org.eclipse.swt.events.TraverseEvent; @@ -47,6 +48,7 @@ import com.gluster.storage.management.client.GlusterDataModelManager; import com.gluster.storage.management.client.UsersClient; import com.gluster.storage.management.core.model.ConnectionDetails; import com.gluster.storage.management.core.model.Status; +import com.gluster.storage.management.gui.Activator; import com.gluster.storage.management.gui.Application; import com.gluster.storage.management.gui.IImageKeys; import com.gluster.storage.management.gui.dialogs.ClusterSelectionDialog.CLUSTER_MODE; @@ -199,79 +201,74 @@ public class LoginDialog extends Dialog { String password = connectionDetails.getPassword(); UsersClient usersClient = new UsersClient(); - Status loginStatus = usersClient.authenticate(user, password); - if (loginStatus.isSuccess()) { - // authentication successful. close the login dialog and open the next one. - close(); - - ClustersClient clustersClient = new ClustersClient(usersClient.getSecurityToken()); - - IEclipsePreferences preferences = new ConfigurationScope().getNode(Application.PLUGIN_ID); - boolean showClusterSelectionDialog = preferences.getBoolean(PreferenceConstants.P_SHOW_CLUSTER_SELECTION_DIALOG, true); - - String clusterName = null; - if(!showClusterSelectionDialog) { - clusterName = preferences.get(PreferenceConstants.P_DEFAULT_CLUSTER_NAME, null); - if(clusterName == null || clusterName.isEmpty()) { - // Cluster name not available in preferences. Hence we must show the cluster selection dialog. - showClusterSelectionDialog = true; - } - } - - CLUSTER_MODE mode; - String serverName = null; - - if (showClusterSelectionDialog) { - ClusterSelectionDialog clusterDialog = new ClusterSelectionDialog(getParentShell(), - clustersClient.getClusterNames()); - int userAction = clusterDialog.open(); - if (userAction == Window.CANCEL) { - MessageDialog.openError(getShell(), "Login Cancelled", - "User cancelled login at cluster selection. Application will close!"); - cancelPressed(); - return; - } - mode = clusterDialog.getClusterMode(); - clusterName = clusterDialog.getClusterName(); - serverName = clusterDialog.getServerName(); + try { + usersClient.authenticate(user, password); + } catch(Exception e) { + MessageDialog.openError(getShell(), "Authentication Failed", e.getMessage()); + setReturnCode(RETURN_CODE_ERROR); + return; + } + + // authentication successful. close the login dialog and open the next one. + close(); + + ClustersClient clustersClient = new ClustersClient(usersClient.getSecurityToken()); + + IPreferenceStore preferenceStore = Activator.getDefault().getPreferenceStore(); + boolean showClusterSelectionDialog = preferenceStore.getBoolean(PreferenceConstants.P_SHOW_CLUSTER_SELECTION_DIALOG); + + CLUSTER_MODE mode; + String clusterName = null; + if (!showClusterSelectionDialog) { + clusterName = preferenceStore.getString(PreferenceConstants.P_DEFAULT_CLUSTER_NAME); + if (clusterName == null || clusterName.isEmpty()) { + // Cluster name not available in preferences. Hence we must show the cluster selection dialog. + showClusterSelectionDialog = true; } else { mode = CLUSTER_MODE.SELECT; } - - try { - createOrRegisterCluster(clustersClient, clusterName, serverName, mode); - GlusterDataModelManager.getInstance().initializeModel(usersClient.getSecurityToken(), clusterName); - super.okPressed(); - } catch (Exception e) { - setReturnCode(RETURN_CODE_ERROR); - MessageDialog.openError(getShell(), "Initialization Error", e.getMessage()); - close(); - } - } else { - MessageDialog.openError(getShell(), "Authentication Failed", loginStatus.getMessage()); } - } - public void createOrRegisterCluster(ClustersClient clustersClient, String clusterName, String serverName, - CLUSTER_MODE mode) { - String errTitle = null; + String serverName = null; - try { - switch (mode) { - case SELECT: + if (showClusterSelectionDialog) { + ClusterSelectionDialog clusterDialog = new ClusterSelectionDialog(getParentShell(), + clustersClient.getClusterNames()); + int userAction = clusterDialog.open(); + if (userAction == Window.CANCEL) { + MessageDialog.openError(getShell(), "Login Cancelled", + "User cancelled login at cluster selection. Application will close!"); + cancelPressed(); return; - case CREATE: - errTitle = "Cluster Creation Failed!"; - clustersClient.createCluster(clusterName); - break; - case REGISTER: - errTitle = "Cluster Registration Failed!"; - clustersClient.registerCluster(clusterName, serverName); - break; } + mode = clusterDialog.getClusterMode(); + clusterName = clusterDialog.getClusterName(); + serverName = clusterDialog.getServerName(); + } else { + mode = CLUSTER_MODE.SELECT; + } + + try { + createOrRegisterCluster(clustersClient, clusterName, serverName, mode); + GlusterDataModelManager.getInstance().initializeModel(usersClient.getSecurityToken(), clusterName); + super.okPressed(); } catch (Exception e) { - MessageDialog.openError(getShell(), errTitle, e.getMessage()); setReturnCode(RETURN_CODE_ERROR); + MessageDialog.openError(getShell(), "Gluster Management Console", e.getMessage()); + } + } + + public void createOrRegisterCluster(ClustersClient clustersClient, String clusterName, String serverName, + CLUSTER_MODE mode) { + switch (mode) { + case SELECT: + return; + case CREATE: + clustersClient.createCluster(clusterName); + break; + case REGISTER: + clustersClient.registerCluster(clusterName, serverName); + break; } } } diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/MigrateDiskPage1.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/MigrateDiskPage1.java index ba5ef867..4533ca23 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/MigrateDiskPage1.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/MigrateDiskPage1.java @@ -23,13 +23,16 @@ import java.util.List; import org.eclipse.jface.layout.TableColumnLayout; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.ColumnWeightData; +import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.wizard.WizardPage; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Table; @@ -62,6 +65,8 @@ public class MigrateDiskPage1 extends WizardPage { private TableViewer tableViewerFrom; + private Button autoCompleteCheckbox; + private ITableLabelProvider getDiskLabelProvider(final String volumeName) { return new TableLabelProviderAdapter() { @@ -74,9 +79,9 @@ public class MigrateDiskPage1 extends WizardPage { return (columnIndex == DISK_TABLE_COLUMN_INDICES.SERVER.ordinal() ? disk.getServerName() : columnIndex == DISK_TABLE_COLUMN_INDICES.BRICK_DIRECTORY.ordinal() ? disk.getMountPoint() + "/" + volumeName : columnIndex == DISK_TABLE_COLUMN_INDICES.FREE_SPACE.ordinal() ? NumberUtil - .formatNumber(disk.getFreeSpace()) + .formatNumber(disk.getFreeSpace() / 1024 ) /* Coverted to GB */ : columnIndex == DISK_TABLE_COLUMN_INDICES.TOTAL_SPACE.ordinal() ? NumberUtil - .formatNumber(disk.getSpace()) : "Invalid"); + .formatNumber(disk.getSpace() / 1024) : "Invalid"); } }; } @@ -118,10 +123,6 @@ public class MigrateDiskPage1 extends WizardPage { this.volume = volume; this.fromBrick = brick; setTitle("Migrate Brick [" + volume.getName() + "]"); - // setDescription("Migrate data from one disk to another for the chosen Volume. " + - // "This will copy all data present in the \"from disk\" of the volume " + - // "to \"to disk\", remove \"from disk\" from the volume, and " + - // "add \"to disk\" to the volume"); setPageDescription(null, null); setPageComplete(false); } @@ -162,12 +163,18 @@ public class MigrateDiskPage1 extends WizardPage { return tableViewerComposite; } - public Disk getSourceDisk() { - return getSelectedDisk(tableViewerFrom); + public String getSourceBrickDir() { + Disk sourceDisk = getSelectedDisk(tableViewerFrom); + return sourceDisk.getQualifiedBrickName(volume.getName()); } - public Disk getTargetDisk() { - return getSelectedDisk(tableViewerTo); + public String getTargetBrickDir() { + Disk targetDisk = getSelectedDisk(tableViewerTo); + return targetDisk.getQualifiedBrickName(volume.getName()); + } + + public Boolean getAutoCommitSelection() { + return autoCompleteCheckbox.getSelection(); } /** @@ -200,7 +207,7 @@ public class MigrateDiskPage1 extends WizardPage { GlusterDataModelManager glusterDataModelManager = GlusterDataModelManager.getInstance(); List<Disk> fromBricks = glusterDataModelManager.getReadyDisksOfVolume(volume); - List<Disk> toDisks = glusterDataModelManager.getReadyDisksOfAllServersExcluding( glusterDataModelManager.getReadyDisksOfVolume(volume)); + List<Disk> toDisks = glusterDataModelManager.getReadyDisksOfAllServersExcluding( fromBricks ); tableViewerFrom = createTableViewer(container, diskLabelProvider, fromBricks, txtFilterFrom); @@ -208,6 +215,17 @@ public class MigrateDiskPage1 extends WizardPage { setFromDisk(tableViewerFrom, fromBrick); } tableViewerTo = createTableViewer(container, diskLabelProvider, toDisks, txtFilterTo); + + // Auto commit selection field + Composite autoCommitContainer = new Composite(container, SWT.NONE); + GridData data = new GridData(); + data.horizontalSpan = 2; + autoCommitContainer.setLayoutData(data); + autoCompleteCheckbox = new Button(autoCommitContainer, SWT.CHECK); + autoCompleteCheckbox.setSelection(true); + Label lblAutoComplete = new Label(autoCommitContainer, SWT.NONE); + lblAutoComplete.setText("Auto commit on migration complete"); + autoCommitContainer.setLayout( container.getLayout()); } private void setFromDisk(TableViewer tableViewer, Brick brickToSelect) { @@ -220,9 +238,17 @@ public class MigrateDiskPage1 extends WizardPage { } } } + + private void refreshButtonStatus() { + if(tableViewerFrom.getSelection().isEmpty() || tableViewerTo.getSelection().isEmpty()) { + setPageComplete(false); + } else { + setPageComplete(true); + } + } private TableViewer createTableViewer(Composite container, ITableLabelProvider diskLabelProvider, - List<Disk> fromDisks, Text txtFilterText) { + List<Disk> bricks, Text txtFilterText) { Composite tableViewerComposite = createTableViewerComposite(container); TableViewer tableViewer = new TableViewer(tableViewerComposite, SWT.SINGLE); @@ -232,7 +258,15 @@ public class MigrateDiskPage1 extends WizardPage { setupDiskTable(tableViewerComposite, tableViewer.getTable()); guiHelper.createFilter(tableViewer, txtFilterText, false); - tableViewer.setInput(fromDisks.toArray()); + tableViewer.setInput(bricks.toArray()); + + tableViewer.addSelectionChangedListener(new ISelectionChangedListener() { + + @Override + public void selectionChanged(SelectionChangedEvent event) { + refreshButtonStatus(); + } + }); return tableViewer; } diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/MigrateDiskWizard.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/MigrateDiskWizard.java index 60cbd387..2d65a869 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/MigrateDiskWizard.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/MigrateDiskWizard.java @@ -18,12 +18,16 @@ *******************************************************************************/ package com.gluster.storage.management.gui.dialogs; +import java.net.URI; + +import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.wizard.Wizard; import com.gluster.storage.management.client.GlusterDataModelManager; +import com.gluster.storage.management.client.TasksClient; import com.gluster.storage.management.client.VolumesClient; import com.gluster.storage.management.core.model.Brick; -import com.gluster.storage.management.core.model.Disk; +import com.gluster.storage.management.core.model.TaskInfo; import com.gluster.storage.management.core.model.Volume; public class MigrateDiskWizard extends Wizard { @@ -47,14 +51,24 @@ public class MigrateDiskWizard extends Wizard { @Override public boolean performFinish() { - Disk sourceDisk = page.getSourceDisk(); - Disk targetDisk = page.getTargetDisk(); - Boolean autoCommit = true; //TODO get auto commit from user selection - // TODO add custom confirm dialog - + String sourceDir = page.getSourceBrickDir(); + String targetDir = page.getTargetBrickDir(); + Boolean autoCommit = page.getAutoCommitSelection(); VolumesClient volumesClient = new VolumesClient(); - volumesClient.startMigration(volume.getName(), sourceDisk.getQualifiedName(), targetDisk.getQualifiedName(), autoCommit); - + + try { + URI uri = volumesClient.startMigration(volume.getName(), sourceDir, targetDir, autoCommit); + + // To get the object + TasksClient taskClient = new TasksClient(); + TaskInfo taskInfo = taskClient.getTaskInfo(uri); + if (taskInfo != null && taskInfo instanceof TaskInfo) { + GlusterDataModelManager.getInstance().getModel().getCluster().addTaskInfo(taskInfo); + } + MessageDialog.openInformation(getShell(), "Brick migration", "Brick migration started successfully"); + } catch (Exception e) { + MessageDialog.openError(getShell(), "Error: Migrate brick", e.getMessage()); + } return true; } } diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/preferences/GlusterPreferencePage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/preferences/GlusterPreferencePage.java index 23b2cff2..431a8128 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/preferences/GlusterPreferencePage.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/preferences/GlusterPreferencePage.java @@ -18,10 +18,16 @@ *******************************************************************************/ package com.gluster.storage.management.gui.preferences; -import org.eclipse.jface.preference.*; -import org.eclipse.ui.IWorkbenchPreferencePage; +import java.util.List; + +import org.eclipse.jface.preference.BooleanFieldEditor; +import org.eclipse.jface.preference.ComboFieldEditor; +import org.eclipse.jface.preference.FieldEditorPreferencePage; +import org.eclipse.jface.preference.IntegerFieldEditor; import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPreferencePage; +import com.gluster.storage.management.client.ClustersClient; import com.gluster.storage.management.gui.Activator; /** @@ -37,15 +43,16 @@ import com.gluster.storage.management.gui.Activator; * the main plug-in class. That way, preferences can * be accessed directly via the preference store. */ - public class GlusterPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage { + + private List<String> clusterNames; public GlusterPreferencePage() { super(GRID); setPreferenceStore(Activator.getDefault().getPreferenceStore()); - setDescription("A demonstration of a preference page implementation"); + setDescription("Gluster Management Console"); } /** @@ -55,29 +62,29 @@ public class GlusterPreferencePage * restore itself. */ public void createFieldEditors() { - addField(new DirectoryFieldEditor(PreferenceConstants.P_PATH, - "&Directory preference:", getFieldEditorParent())); addField( new BooleanFieldEditor( - PreferenceConstants.P_BOOLEAN, - "&An example of a boolean preference", + PreferenceConstants.P_SHOW_CLUSTER_SELECTION_DIALOG, + "&Show Cluster Selection Dialog on Login:", getFieldEditorParent())); + + String[][] clusterNamesArr = new String[clusterNames.size()][2]; + for(int i = 0; i < clusterNames.size(); i++) { + String clusterName = clusterNames.get(i);; + clusterNamesArr[i][0] = clusterName; + clusterNamesArr[i][1] = clusterName; + } - addField(new RadioGroupFieldEditor( - PreferenceConstants.P_CHOICE, - "An example of a multiple-choice preference", - 1, - new String[][] { { "&Choice 1", "choice1" }, { - "C&hoice 2", "choice2" } - }, getFieldEditorParent())); - addField( - new StringFieldEditor(PreferenceConstants.P_STRING, "A &text preference:", getFieldEditorParent())); + addField(new ComboFieldEditor(PreferenceConstants.P_DEFAULT_CLUSTER_NAME, "Default &Cluster to manage:", + clusterNamesArr, getFieldEditorParent())); + addField(new IntegerFieldEditor(PreferenceConstants.P_DATA_REFRESH_INTERVAL, "&Data Refresh Interval:", + getFieldEditorParent())); } /* (non-Javadoc) * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench) */ public void init(IWorkbench workbench) { + clusterNames = new ClustersClient().getClusterNames(); } - -}
\ No newline at end of file +} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/preferences/PreferenceConstants.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/preferences/PreferenceConstants.java index 8b5a8cfd..260aadb6 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/preferences/PreferenceConstants.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/preferences/PreferenceConstants.java @@ -25,6 +25,7 @@ public class PreferenceConstants { public static final String P_SHOW_CLUSTER_SELECTION_DIALOG = "show.cluster.selection.dialog"; public static final String P_DEFAULT_CLUSTER_NAME = "default.cluster.name"; + public static final String P_DATA_REFRESH_INTERVAL = "data.refresh.interval"; // TODO: Remove after proper preferences are added public static final String P_PATH = "pathPreference"; diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/preferences/PreferenceInitializer.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/preferences/PreferenceInitializer.java index 74ace130..1a4104ac 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/preferences/PreferenceInitializer.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/preferences/PreferenceInitializer.java @@ -35,10 +35,7 @@ public class PreferenceInitializer extends AbstractPreferenceInitializer { */ public void initializeDefaultPreferences() { IPreferenceStore store = Activator.getDefault().getPreferenceStore(); - store.setDefault(PreferenceConstants.P_BOOLEAN, true); - store.setDefault(PreferenceConstants.P_CHOICE, "choice2"); - store.setDefault(PreferenceConstants.P_STRING, - "Default value"); + + store.setDefault(PreferenceConstants.P_SHOW_CLUSTER_SELECTION_DIALOG, true); } - } diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/GUIHelper.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/GUIHelper.java index ac29ecf0..d6fd5d03 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/GUIHelper.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/GUIHelper.java @@ -84,6 +84,7 @@ import com.gluster.storage.management.core.utils.JavaUtil; import com.gluster.storage.management.gui.Application; import com.gluster.storage.management.gui.IImageKeys; import com.gluster.storage.management.gui.views.NavigationView; +import com.gluster.storage.management.gui.views.TasksView; public class GUIHelper { private static final GUIHelper instance = new GUIHelper(); @@ -416,6 +417,7 @@ public class GUIHelper { return selectedEntities; } + public void configureCheckboxTableViewer(final CheckboxTableViewer tableViewer) { tableViewer.addCheckStateListener(new ICheckStateListener() { @@ -450,6 +452,16 @@ public class GUIHelper { } } + public void showTaskView() { + try { + PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage() + .showView( TasksView.ID ); + } catch (PartInitException e) { + e.printStackTrace(); + throw new GlusterRuntimeException("Could not open the task progress view!", e); + } + } + public void setStatusMessage(String message) { Application.getApplication().getStatusLineManager().setMessage(message); } diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/DiscoveredServerView.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/DiscoveredServerView.java index fdb4c53c..8516d1db 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/DiscoveredServerView.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/DiscoveredServerView.java @@ -62,7 +62,7 @@ public class DiscoveredServerView extends ViewPart { toolkit.createLabel(section, "" + server.getNumOfCPUs(), SWT.NONE); toolkit.createLabel(section, "Total Memory (GB): ", SWT.NONE); - toolkit.createLabel(section, "" + (server.getTotalMemory() / 1024), SWT.NONE); + toolkit.createLabel(section, "" + NumberUtil.formatNumber((server.getTotalMemory() / 1024)), SWT.NONE); toolkit.createLabel(section, "Total Disk Space (GB): ", SWT.NONE); toolkit.createLabel(section, "" + NumberUtil.formatNumber((server.getTotalDiskSpace() / 1024)), SWT.NONE); diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterViewsManager.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterViewsManager.java index b4b31a0a..ab1e55ab 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterViewsManager.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterViewsManager.java @@ -29,6 +29,7 @@ import com.gluster.storage.management.core.model.Entity; import com.gluster.storage.management.core.model.EntityGroup; import com.gluster.storage.management.core.model.GlusterServer; import com.gluster.storage.management.core.model.Server; +import com.gluster.storage.management.core.model.TaskInfo; import com.gluster.storage.management.core.model.Volume; /** @@ -80,6 +81,7 @@ public class GlusterViewsManager implements ViewsManager { private void showViewsForCluster(Cluster cluster) throws PartInitException { page.showView(ClusterSummaryView.ID); + page.showView(TasksView.ID, null, IWorkbenchPage.VIEW_CREATE); } private void showViewsForVolume(Volume volume) throws PartInitException { diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/TasksView.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/TasksView.java new file mode 100644 index 00000000..fb772d46 --- /dev/null +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/TasksView.java @@ -0,0 +1,39 @@ +package com.gluster.storage.management.gui.views; + +import java.util.List; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.part.ViewPart; + +import com.gluster.storage.management.client.GlusterDataModelManager; +import com.gluster.storage.management.core.model.TaskInfo; +import com.gluster.storage.management.gui.views.pages.TasksPage; + +public class TasksView extends ViewPart { + + public static final String ID = TasksView.class.getName(); + private TasksPage page; + + + public TasksView() { + // TODO Auto-generated constructor stub + } + + @Override + public void createPartControl(Composite parent) { + page = new TasksPage(getSite(), parent, SWT.NONE, getAllTasks()); + page.layout(); // IMP: lays out the form properly + } + + + private List<TaskInfo> getAllTasks() { + return GlusterDataModelManager.getInstance().getModel().getCluster().getTaskInfoList(); + } + + @Override + public void setFocus() { + page.setFocus(); + } + +} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumesSummaryView.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumesSummaryView.java index 311014a0..a43330c4 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumesSummaryView.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumesSummaryView.java @@ -35,8 +35,8 @@ import com.gluster.storage.management.client.GlusterDataModelManager; import com.gluster.storage.management.core.model.Alert; import com.gluster.storage.management.core.model.Cluster; import com.gluster.storage.management.core.model.EntityGroup; -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.TaskInfo.TASK_TYPE; import com.gluster.storage.management.core.model.Volume; import com.gluster.storage.management.core.model.Volume.VOLUME_STATUS; import com.gluster.storage.management.gui.IImageKeys; diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractDisksPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractDisksPage.java index 133aed38..221e82b1 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractDisksPage.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractDisksPage.java @@ -38,6 +38,7 @@ import org.eclipse.ui.forms.events.HyperlinkAdapter; import org.eclipse.ui.forms.events.HyperlinkEvent; import org.eclipse.ui.forms.widgets.ImageHyperlink; +import com.gluster.storage.management.client.GlusterServersClient; import com.gluster.storage.management.core.model.ClusterListener; import com.gluster.storage.management.core.model.DefaultClusterListener; import com.gluster.storage.management.core.model.Disk; @@ -56,7 +57,7 @@ public abstract class AbstractDisksPage extends AbstractTableViewerPage<Disk> im protected abstract int getStatusColumnIndex(); public AbstractDisksPage(final Composite parent, int style, IWorkbenchSite site, List<Disk> disks) { - super(site, parent, style, disks); + super(site, parent, style, true, true, disks); this.disks = disks; // creates hyperlinks for "unitialized" disks @@ -199,8 +200,11 @@ public abstract class AbstractDisksPage extends AbstractTableViewerPage<Disk> im @Override public void linkActivated(HyperlinkEvent e) { updateStatus(DISK_STATUS.INITIALIZING, true); + + GlusterServersClient serversClient = new GlusterServersClient(); + serversClient.initializeDisk(disk.getServerName(), disk.getName()); + guiHelper.showProgressView(); - new InitializeDiskJob(disk).schedule(); } } diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractTableViewerPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractTableViewerPage.java index dfa06f85..a37773e1 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractTableViewerPage.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractTableViewerPage.java @@ -26,6 +26,7 @@ import org.eclipse.jface.viewers.IBaseLabelProvider; import org.eclipse.jface.viewers.IContentProvider; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.viewers.TableViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; @@ -50,15 +51,20 @@ import com.gluster.storage.management.gui.utils.GUIHelper; public abstract class AbstractTableViewerPage<T> extends Composite { protected final FormToolkit toolkit = new FormToolkit(Display.getCurrent()); - protected CheckboxTableViewer tableViewer; + protected TableViewer tableViewer; + private boolean useCheckboxes; + private boolean multiSelection; protected GUIHelper guiHelper = GUIHelper.getInstance(); protected Composite parent; private Hyperlink linkAll, linkNone; - public AbstractTableViewerPage(IWorkbenchSite site, final Composite parent, int style, Object model) { + public AbstractTableViewerPage(IWorkbenchSite site, final Composite parent, int style, boolean useChechboxes, boolean multiSelection, Object model) { super(parent, style); this.parent = parent; + + this.useCheckboxes = useChechboxes; + this.multiSelection = multiSelection; toolkit.adapt(this); toolkit.paintBordersFor(this); @@ -69,7 +75,7 @@ public abstract class AbstractTableViewerPage<T> extends Composite { Text filterText = guiHelper.createFilterText(toolkit, this); - setupServerTableViewer(site, filterText); + setupTableViewer(site, filterText); tableViewer.setInput(model); parent.layout(); // Important - this actually paints the table @@ -78,27 +84,35 @@ public abstract class AbstractTableViewerPage<T> extends Composite { } public void createCheckboxSelectionLinks() { - // create the "select all/none" links - toolkit.createLabel(this, "Select"); - linkAll = toolkit.createHyperlink(this, "all", SWT.NONE); - linkAll.addHyperlinkListener(new HyperlinkAdapter() { - @Override - public void linkActivated(org.eclipse.ui.forms.events.HyperlinkEvent e) { - tableViewer.setAllChecked(true); - tableViewer.setSelection(new StructuredSelection(getAllEntities())); - } - }); - - toolkit.createLabel(this, " / "); - - linkNone = toolkit.createHyperlink(this, "none", SWT.NONE); - linkNone.addHyperlinkListener(new HyperlinkAdapter() { - @Override - public void linkActivated(org.eclipse.ui.forms.events.HyperlinkEvent e) { - tableViewer.setAllChecked(false); - tableViewer.setSelection(null); - } - }); + if (useCheckboxes) { + // create the "select all/none" links + toolkit.createLabel(this, "Select"); + linkAll = toolkit.createHyperlink(this, "all", SWT.NONE); + linkAll.addHyperlinkListener(new HyperlinkAdapter() { + @Override + public void linkActivated(org.eclipse.ui.forms.events.HyperlinkEvent e) { + ((CheckboxTableViewer) tableViewer).setAllChecked(true); + tableViewer.setSelection(new StructuredSelection(getAllEntities())); + } + }); + + toolkit.createLabel(this, " / "); + + linkNone = toolkit.createHyperlink(this, "none", SWT.NONE); + linkNone.addHyperlinkListener(new HyperlinkAdapter() { + @Override + public void linkActivated(org.eclipse.ui.forms.events.HyperlinkEvent e) { + ((CheckboxTableViewer) tableViewer).setAllChecked(false); + tableViewer.setSelection(null); + } + }); + } else { + // create dummy labels to maintain layout + toolkit.createLabel(this, ""); + toolkit.createLabel(this, ""); + toolkit.createLabel(this, ""); + toolkit.createLabel(this, ""); + } } private void createListeners(final Composite parent) { @@ -145,7 +159,7 @@ public abstract class AbstractTableViewerPage<T> extends Composite { setLayout(layout); } - private void setupServerTable(Composite parent, Table table) { + protected void setupTable(Composite parent, Table table) { table.setHeaderVisible(true); table.setLinesVisible(false); @@ -155,15 +169,19 @@ public abstract class AbstractTableViewerPage<T> extends Composite { setColumnProperties(table); } - private CheckboxTableViewer createServerTableViewer(Composite parent) { - CheckboxTableViewer tableViewer = CheckboxTableViewer.newCheckList(parent, SWT.FLAT | SWT.FULL_SELECTION | SWT.MULTI); + private void createTableViewer(Composite parent) { + int style = SWT.FLAT | SWT.FULL_SELECTION; + style |= (multiSelection ? SWT.MULTI : SWT.SINGLE); + + if(useCheckboxes) { + tableViewer = CheckboxTableViewer.newCheckList(parent, style); + } else { + tableViewer = new TableViewer(parent, style); + } tableViewer.setLabelProvider(getLabelProvider()); tableViewer.setContentProvider(getContentProvider()); - - setupServerTable(parent, tableViewer.getTable()); - - return tableViewer; + setupTable(parent, tableViewer.getTable()); } private Composite createTableViewerComposite() { @@ -182,13 +200,15 @@ public abstract class AbstractTableViewerPage<T> extends Composite { return tableViewerComposite; } - private void setupServerTableViewer(IWorkbenchSite site, final Text filterText) { + private void setupTableViewer(IWorkbenchSite site, final Text filterText) { Composite tableViewerComposite = createTableViewerComposite(); - tableViewer = createServerTableViewer(tableViewerComposite); + createTableViewer(tableViewerComposite); site.setSelectionProvider(tableViewer); - // make sure that table selection is driven by checkbox selection - guiHelper.configureCheckboxTableViewer(tableViewer); + if(useCheckboxes) { + // make sure that table selection is driven by checkbox selection + guiHelper.configureCheckboxTableViewer((CheckboxTableViewer)tableViewer); + } // Create a case insensitive filter for the table viewer using the filter text field guiHelper.createFilter(tableViewer, filterText, false); diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/BricksPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/BricksPage.java index b83914eb..9805daec 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/BricksPage.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/BricksPage.java @@ -47,7 +47,7 @@ public class BricksPage extends AbstractTableViewerPage<Brick> { "Total Space (GB)", "Status" }; public BricksPage(Composite parent, int style, IWorkbenchSite site, final List<Brick> bricks) { - super(site, parent, style, bricks); + super(site, parent, style, true, true, bricks); this.bricks = bricks; } diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/GlusterServersPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/GlusterServersPage.java index 87644622..be4df7ad 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/GlusterServersPage.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/GlusterServersPage.java @@ -49,7 +49,7 @@ public class GlusterServersPage extends AbstractTableViewerPage<GlusterServer> { "IP Address(es)", "Number\nof CPUs", "Total\nMemory (GB)", "Free Space (GB)", "Total \n Space (GB)", "Status" }; // Removed "Preferred\nNetwork", public GlusterServersPage(IWorkbenchSite site, final Composite parent, int style, final EntityGroup<GlusterServer> servers) { - super(site, parent, style, servers); + super(site, parent, style, true, true, servers); this.glusterServers = servers.getEntities(); } diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/ServerLogsPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/ServerLogsPage.java index 7cde38bb..0ff22e31 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/ServerLogsPage.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/ServerLogsPage.java @@ -26,6 +26,8 @@ import org.eclipse.jface.viewers.ListViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.events.VerifyEvent; +import org.eclipse.swt.events.VerifyListener; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; @@ -84,6 +86,27 @@ public class ServerLogsPage extends Composite { text = toolkit.createText(composite, "100", SWT.NONE); text.setBounds(85, 15, 60, 20); + text.setTextLimit(4); + text.addVerifyListener(new VerifyListener() { + + @Override + public void verifyText(VerifyEvent event) { + // Assume we allow it + event.doit = true; + + String text = event.text; + char[] chars = text.toCharArray(); + + // Don't allow if text contains non-digit characters + for (int i = 0; i < chars.length; i++) { + if (!Character.isDigit(chars[i])) { + event.doit = false; + break; + } + } + + } + }); Label lblMessagesAndFilter = toolkit.createLabel(composite, " messages from ", SWT.CENTER); lblMessagesAndFilter.setBounds(160, 15, 110, 20); diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/ServersPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/ServersPage.java index 48b8892c..f285dd9f 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/ServersPage.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/ServersPage.java @@ -55,7 +55,7 @@ public class ServersPage extends AbstractTableViewerPage<Server> { // "Total Disk\n Space (GB)", "Disk Space\nin Use (GB)"}; public ServersPage(final Composite parent, IWorkbenchSite site, EntityGroup<Server> serversGroup) { - super(site, parent, SWT.NONE, serversGroup); + super(site, parent, SWT.NONE, true, true, serversGroup); this.servers = serversGroup.getEntities(); } diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/TasksPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/TasksPage.java new file mode 100644 index 00000000..ce68e22f --- /dev/null +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/TasksPage.java @@ -0,0 +1,117 @@ +/** + * TasksPage.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.gui.views.pages; + +import java.util.List; + +import org.eclipse.jface.viewers.ArrayContentProvider; +import org.eclipse.jface.viewers.IBaseLabelProvider; +import org.eclipse.jface.viewers.IContentProvider; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Table; +import org.eclipse.ui.IWorkbenchSite; + +import com.gluster.storage.management.core.model.ClusterListener; +import com.gluster.storage.management.core.model.DefaultClusterListener; +import com.gluster.storage.management.core.model.TaskInfo; +import com.gluster.storage.management.gui.TasksTableLabelProvider; + +public class TasksPage extends AbstractTableViewerPage<TaskInfo> { + private List<TaskInfo> taskInfoList; + + public enum TASK_TABLE_COLUMN_INDICES { + TASK, STATUS + }; + + private static final String[] TASK_TABLE_COLUMN_NAMES = new String[] { "Task", "Status"}; + + + @SuppressWarnings("unchecked") + public TasksPage(IWorkbenchSite site, Composite parent, int style, Object taskInfo) { + super(site, parent, style, false, false, taskInfo); + this.taskInfoList = (List<TaskInfo>) taskInfo; + } + + /* (non-Javadoc) + * @see com.gluster.storage.management.gui.views.pages.AbstractTableViewerPage#createClusterListener() + */ + @Override + protected ClusterListener createClusterListener() { + return new DefaultClusterListener() { + @Override + public void taskAdded(TaskInfo taskInfo) { + refreshViewer(); + } + + @Override + public void taskRemoved(TaskInfo taskInfo) { + refreshViewer(); + } + + private void refreshViewer() { + tableViewer.refresh(); + parent.update(); + } + }; + } + + /* (non-Javadoc) + * @see com.gluster.storage.management.gui.views.pages.AbstractTableViewerPage#getColumnNames() + */ + @Override + protected String[] getColumnNames() { + return TASK_TABLE_COLUMN_NAMES; + } + + /* (non-Javadoc) + * @see com.gluster.storage.management.gui.views.pages.AbstractTableViewerPage#setColumnProperties(org.eclipse.swt.widgets.Table) + */ + @Override + protected void setColumnProperties(Table table) { + guiHelper.setColumnProperties(table, TASK_TABLE_COLUMN_INDICES.TASK.ordinal(), SWT.LEFT, 50); + guiHelper.setColumnProperties(table, TASK_TABLE_COLUMN_INDICES.STATUS.ordinal(), SWT.LEFT, 50); + } + + /* (non-Javadoc) + * @see com.gluster.storage.management.gui.views.pages.AbstractTableViewerPage#getLabelProvider() + */ + @Override + protected IBaseLabelProvider getLabelProvider() { + return new TasksTableLabelProvider(); + } + + /* (non-Javadoc) + * @see com.gluster.storage.management.gui.views.pages.AbstractTableViewerPage#getContentProvider() + */ + @Override + protected IContentProvider getContentProvider() { + return new ArrayContentProvider(); + } + + /* (non-Javadoc) + * @see com.gluster.storage.management.gui.views.pages.AbstractTableViewerPage#getAllEntities() + */ + @Override + protected List<TaskInfo> getAllEntities() { + return taskInfoList; + } +} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/VolumeLogsPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/VolumeLogsPage.java index 6ba9c0d1..82836621 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/VolumeLogsPage.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/VolumeLogsPage.java @@ -32,6 +32,8 @@ import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.VerifyEvent; +import org.eclipse.swt.events.VerifyListener; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; @@ -334,6 +336,26 @@ public class VolumeLogsPage extends Composite { private void createLineCountText(Composite composite) { lineCountText = toolkit.createText(composite, "100", SWT.NONE); lineCountText.setBounds(85, 15, 60, 20); + lineCountText.setTextLimit(4); + lineCountText.addVerifyListener(new VerifyListener() { + + @Override + public void verifyText(VerifyEvent event) { + // Assume we allow it + event.doit = true; + + String text = event.text; + char[] chars = text.toCharArray(); + + // Don't allow if text contains non-digit characters + for (int i = 0; i < chars.length; i++) { + if (!Character.isDigit(chars[i])) { + event.doit = false; + break; + } + } + } + }); } private void createLineCountLabel(Composite composite) { diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/VolumeOptionsPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/VolumeOptionsPage.java index bd003f3b..956fc215 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/VolumeOptionsPage.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/VolumeOptionsPage.java @@ -40,6 +40,7 @@ import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; @@ -91,9 +92,9 @@ public class VolumeOptionsPage extends Composite { toolkit.paintBordersFor(this); setupPageLayout(); + addTopButton = createAddButton(); filterText = guiHelper.createFilterText(toolkit, this); - addTopButton = createAddButton(); setupOptionsTableViewer(filterText); addBottomButton = createAddButton(); @@ -114,48 +115,7 @@ public class VolumeOptionsPage extends Composite { } private Button createAddButton() { - Button button = toolkit.createButton(this, "&Add", SWT.FLAT); - button.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - // add an empty option to be filled up by user - volume.setOption("", ""); - - tableViewer.refresh(); - tableViewer.setSelection(new StructuredSelection(getEntry(""))); - keyColumn.getViewer().editElement(getEntry(""), 0); // edit newly created entry - - // disable the add button AND search filter textbox till user fills up the new option - setAddButtonsEnabled(false); - filterText.setEnabled(false); - } - - private Entry<String, String> getEntry(String key) { - for (Entry<String, String> entry : volume.getOptions().entrySet()) { - if (entry.getKey().equals(key)) { - return entry; - } - } - return null; - } - }); - - // Make sure that add button is enabled only when search filter textbox is empty - filterText.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent e) { - if (filterText.getText().length() > 0) { - setAddButtonsEnabled(false); - } else { - if (defaultVolumeOptions.size() == volume.getOptions().size()) { - setAddButtonsEnabled(false); - } else { - setAddButtonsEnabled(true); - } - } - } - }); - return button; + return toolkit.createButton(this, "&Add", SWT.FLAT); } private void registerListeners(final Composite parent) { @@ -243,11 +203,55 @@ public class VolumeOptionsPage extends Composite { return optionKey.equals(volume.getOptions().keySet().toArray()[volume.getOptions().size() - 1]); } }; + + SelectionListener addButtonSelectionListener = new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + // add an empty option to be filled up by user + volume.setOption("", ""); + + tableViewer.refresh(); + tableViewer.setSelection(new StructuredSelection(getEntry(""))); + keyColumn.getViewer().editElement(getEntry(""), 0); // edit newly created entry + + // disable the add button AND search filter textbox till user fills up the new option + setAddButtonsEnabled(false); + filterText.setEnabled(false); + } + + private Entry<String, String> getEntry(String key) { + for (Entry<String, String> entry : volume.getOptions().entrySet()) { + if (entry.getKey().equals(key)) { + return entry; + } + } + return null; + } + }; + addTopButton.addSelectionListener(addButtonSelectionListener); + addBottomButton.addSelectionListener(addButtonSelectionListener); + + // Make sure that add button is enabled only when search filter textbox is empty + filterText.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + if (filterText.getText().length() > 0) { + setAddButtonsEnabled(false); + } else { + if (defaultVolumeOptions.size() == volume.getOptions().size()) { + setAddButtonsEnabled(false); + } else { + setAddButtonsEnabled(true); + } + } + } + }); + GlusterDataModelManager.getInstance().addClusterListener(clusterListener); } private void setupPageLayout() { - final GridLayout layout = new GridLayout(1, false); + final GridLayout layout = new GridLayout(2, false); layout.verticalSpacing = 10; layout.marginTop = 10; setLayout(layout); @@ -256,7 +260,7 @@ public class VolumeOptionsPage extends Composite { private void setupOptionsTable(Composite parent) { Table table = tableViewer.getTable(); table.setHeaderVisible(true); - table.setLinesVisible(false); + table.setLinesVisible(true); TableColumnLayout tableColumnLayout = createTableColumnLayout(); parent.setLayout(tableColumnLayout); @@ -337,7 +341,11 @@ public class VolumeOptionsPage extends Composite { private Composite createTableViewerComposite() { Composite tableViewerComposite = new Composite(this, SWT.NO); tableViewerComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); - tableViewerComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true); + layoutData.horizontalSpan = 2; + tableViewerComposite.setLayoutData(layoutData); + return tableViewerComposite; } diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/VolumesPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/VolumesPage.java index 3a8891d4..33eb6da7 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/VolumesPage.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/VolumesPage.java @@ -48,7 +48,7 @@ public class VolumesPage extends AbstractTableViewerPage<Volume> { "Number of\nBricks", "Transport Type", "Status" }; public VolumesPage(final Composite parent, IWorkbenchSite site, EntityGroup<Volume> volumes) { - super(site, parent, SWT.NONE, volumes); + super(site, parent, SWT.NONE, true, true, volumes); } @Override diff --git a/src/com.gluster.storage.management.server.scripts/src/get_volume_brick_log.py b/src/com.gluster.storage.management.server.scripts/src/get_volume_brick_log.py index 7c912412..fd7361da 100755 --- a/src/com.gluster.storage.management.server.scripts/src/get_volume_brick_log.py +++ b/src/com.gluster.storage.management.server.scripts/src/get_volume_brick_log.py @@ -19,7 +19,7 @@ import re import os import sys -from XmlHandler import ResponseXml +from XmlHandler import XDOM def enumLogType(logCode): if "M" == logCode.upper(): @@ -44,12 +44,12 @@ def enumLogType(logCode): return "UNKNOWN" ##--end of enumLogType() -def addLog(responseDom, logMessageTag, loginfo): - logTag = responseDom.createTag("logMessage", None) - logTag.appendChild(responseDom.createTag("timestamp", loginfo[0] + " " + loginfo[1])) - logTag.appendChild(responseDom.createTag("severity", enumLogType(loginfo[2]))) - logTag.appendChild(responseDom.createTag("message", loginfo[3])) - logMessageTag.appendChild(logTag) +def addLog(responseDom, logMessagesTag, loginfo): + logMessageTag = responseDom.createTag("logMessage") + logMessageTag.appendChild(responseDom.createTag("timestamp", loginfo[0] + " " + loginfo[1])) + logMessageTag.appendChild(responseDom.createTag("severity", enumLogType(loginfo[2]))) + logMessageTag.appendChild(responseDom.createTag("message", loginfo[3])) + logMessagesTag.appendChild(logMessageTag); return True ##--end of addLog() @@ -61,38 +61,32 @@ def logSplit(log): ##--end of logSplit() def getVolumeLog(logFilePath, tailCount): - rs = ResponseXml() + rs = XDOM() if not logFilePath: - rs.appendTagRoute("status.code", "-1") - rs.appendTagRoute("status.message", "No log file path given") - return rs.toprettyxml() + print >> sys.stderr, "No log file path given" + sys.exit(-1); if not tailCount: - rs.appendTagRoute("status.code", "-1") - rs.appendTagRoute("status.message", "No tail count given") - return rs.toprettyxml() + print >> sys.stderr, "No tail count given" + sys.exit(-1); pattern = '\[\d{4}-\d{2}-\d{2}\s{1}\d{2}:\d{2}:\d{2}.\d+\]\s{1}([MACEWNIDT]){1}\s+' - logMessagesTag = rs.createTag("logMessages") if not os.path.exists(logFilePath): - rs.appendTagRoute("status.code", "-1") - rs.appendTagRoute("status.message", "volume log file [%s] not found!" % logFilePath) - return rs.toprettyxml + print >> sys.stderr, "volume log file [%s] not found!" % logFilePath + sys.exit(-1); fp = open(logFilePath) - #lines = [line for line in fp] lines = [line for line in fp if re.match(pattern, line)] fp.close() i = len(lines) - int(tailCount) if i < 0: i = 0 + logMessagesTag = rs.createTag("logMessages") + rs.addTag(logMessagesTag) for log in lines[i:]: loginfo = logSplit(log) addLog(rs, logMessagesTag, loginfo) - rs.appendTagRoute("status.code", "0") - rs.appendTagRoute("status.message", "Success") - rs.appendTag(logMessagesTag) - return rs.toprettyxml() + return rs.toxml() ##--end of getVolumeLog() def main(): 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" /> |
