From f73a94f87bab4088d7b95ee54f98f29b2dd72876 Mon Sep 17 00:00:00 2001 From: Shireesh Anjal Date: Wed, 20 Apr 2011 19:32:00 +0530 Subject: Story#34 - Volume logs - REST server changes --- .../management/core/constants/RESTConstants.java | 11 +++- .../storage/management/core/model/LogMessage.java | 10 ++++ .../storage/management/core/model/Status.java | 5 ++ .../core/response/LogMessageListResponse.java | 42 ++++++++++++++++ .../core/response/VolumeListResponse.java | 4 -- .../server/resources/VolumesResource.java | 58 ++++++++++++++++++++++ .../management/server/utils/ServerUtil.java | 3 +- 7 files changed, 126 insertions(+), 7 deletions(-) create mode 100644 src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/response/LogMessageListResponse.java (limited to 'src') 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 b5b51cfd..3fb22ff6 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 @@ -26,15 +26,22 @@ package com.gluster.storage.management.core.constants; public class RESTConstants { // Volumes Resource public static final String RESOURCE_PATH_VOLUMES = "/cluster/volumes"; + public static final String SUBRESOURCE_DEFAULT_OPTIONS = "defaultoptions"; + public static final String SUBRESOURCE_OPTIONS = "options"; + public static final String SUBRESOURCE_LOGS = "logs"; + + public static final String FORM_PARAM_OPERATION = "operation"; public static final String FORM_PARAM_VALUE_START = "start"; public static final String FORM_PARAM_VALUE_STOP = "stop"; public static final String FORM_PARAM_OPTION_KEY = "key"; public static final String FORM_PARAM_OPTION_VALUE = "value"; + public static final String PATH_PARAM_VOLUME_NAME = "volumeName"; - public static final String SUBRESOURCE_DEFAULT_OPTIONS = "defaultoptions"; - public static final String SUBRESOURCE_OPTIONS = "options"; + public static final String QUERY_PARAM_DISK_NAME = "diskName"; + public static final String QUERY_PARAM_LINE_COUNT = "lineCount"; + // Running tasks resource public static final String RESOURCE_PATH_RUNNING_TASKS = "/cluster/runningtasks"; public static final String RESOURCE_PATH_ALERTS = "/cluster/alerts"; diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/LogMessage.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/LogMessage.java index cc3aa043..d81b8d0f 100644 --- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/LogMessage.java +++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/LogMessage.java @@ -20,14 +20,24 @@ package com.gluster.storage.management.core.model; import java.util.Date; +import javax.xml.bind.annotation.XmlRootElement; + import com.gluster.storage.management.core.utils.StringUtil; +@XmlRootElement public class LogMessage implements Filterable { private Date timestamp; private Disk disk; private String severity; private String message; + public LogMessage() { + } + + public LogMessage(String logMessage) { + // TODO: Parse the log message and extract fields + } + public Date getTimestamp() { return timestamp; } 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 45a9842b..95075f78 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 @@ -59,6 +59,11 @@ public class Status { this.code = result.getExitValue(); this.message = result.getOutput(); } + + public Status(Exception e) { + this.code = STATUS_CODE_FAILURE; + this.message = e.getMessage(); + } @XmlElement(name = "code", type = Integer.class) public Integer getCode() { 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 new file mode 100644 index 00000000..191334d3 --- /dev/null +++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/response/LogMessageListResponse.java @@ -0,0 +1,42 @@ +/** + * + */ +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.XmlElementWrapper; +import javax.xml.bind.annotation.XmlRootElement; + +import com.gluster.storage.management.core.model.LogMessage; +import com.gluster.storage.management.core.model.Status; + +@XmlRootElement(name = "response") +public class LogMessageListResponse extends AbstractResponse { + private List logMessages = new ArrayList(); + + public LogMessageListResponse() { + } + + public LogMessageListResponse(Status status, List logMessages) { + setStatus(status); + setLogMessages(logMessages); + } + + @XmlElementWrapper(name = "logMessages") + @XmlElement(name = "logMessage", type = LogMessage.class) + public List getLogMessages() { + return logMessages; + } + + public void setLogMessages(List 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/VolumeListResponse.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/response/VolumeListResponse.java index fc1c9a6c..97085603 100644 --- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/response/VolumeListResponse.java +++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/response/VolumeListResponse.java @@ -30,10 +30,6 @@ public class VolumeListResponse extends AbstractResponse { return this.volumes; } - /** - * @param volumes - * volumes to set - */ public void setVolumes(List volumes) { this.volumes = volumes; } 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 a4ecfcc6..0bf781cf 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 @@ -24,8 +24,11 @@ import static com.gluster.storage.management.core.constants.RESTConstants.FORM_P import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_VALUE_START; import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_VALUE_STOP; import static com.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_VOLUME_NAME; +import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_DISK_NAME; +import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_LINE_COUNT; import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_PATH_VOLUMES; import static com.gluster.storage.management.core.constants.RESTConstants.SUBRESOURCE_DEFAULT_OPTIONS; +import static com.gluster.storage.management.core.constants.RESTConstants.SUBRESOURCE_LOGS; import static com.gluster.storage.management.core.constants.RESTConstants.SUBRESOURCE_OPTIONS; import java.util.ArrayList; @@ -40,14 +43,18 @@ import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import com.gluster.storage.management.core.constants.CoreConstants; import com.gluster.storage.management.core.constants.RESTConstants; +import com.gluster.storage.management.core.exceptions.GlusterRuntimeException; +import com.gluster.storage.management.core.model.LogMessage; import com.gluster.storage.management.core.model.Status; import com.gluster.storage.management.core.model.Volume; import com.gluster.storage.management.core.model.Volume.TRANSPORT_TYPE; import com.gluster.storage.management.core.response.GenericResponse; +import com.gluster.storage.management.core.response.LogMessageListResponse; import com.gluster.storage.management.core.response.VolumeListResponse; import com.gluster.storage.management.core.response.VolumeOptionInfoListResponse; import com.gluster.storage.management.server.constants.VolumeOptionsDefaults; @@ -61,6 +68,7 @@ import com.sun.jersey.spi.resource.Singleton; public class VolumesResource { 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_DISK_LOG_SCRIPT = "get_volume_disk_log.py"; @InjectParam private static ServerUtil serverUtil; @@ -212,6 +220,56 @@ public class VolumesResource { } return new Status(Status.STATUS_CODE_SUCCESS, "Directories cleaned up successfully!"); } + + private List getDiskLogs(String volumeName, String diskName, Integer lineCount) + throws GlusterRuntimeException { + String[] diskParts = diskName.split(":"); + String server = diskParts[0]; + String disk = diskParts[1]; + + // Usage: get_volume_disk_log.py + Status logStatus = (Status) serverUtil.executeOnServer(true, server, VOLUME_DISK_LOG_SCRIPT + " " + volumeName + + " " + disk + " " + lineCount, Status.class); + if(!logStatus.isSuccess()) { + throw new GlusterRuntimeException(logStatus.toString()); + } + + return extractLogMessages(logStatus.getMessage()); + } + + private List extractLogMessages(String logContent) { + List logMessages = new ArrayList(); + for(String logMessage : logContent.split(CoreConstants.NEWLINE)) { + logMessages.add(new LogMessage(logMessage)); + } + + return logMessages; + } + + @GET + @Path("{" + PATH_PARAM_VOLUME_NAME + "}/" + SUBRESOURCE_LOGS) + public LogMessageListResponse getLogs(@PathParam(PATH_PARAM_VOLUME_NAME) String volumeName, + @QueryParam(QUERY_PARAM_DISK_NAME) String diskName, @QueryParam(QUERY_PARAM_LINE_COUNT) Integer lineCount) { + List logMessages = null; + + try { + if (diskName == null || diskName.isEmpty()) { + logMessages = new ArrayList(); + // fetch logs for every brick of the volume + Volume volume = getVolume(volumeName); + for (String volumeDisk : volume.getDisks()) { + logMessages.addAll(getDiskLogs(volumeName, volumeDisk, lineCount)); + } + } else { + // fetch logs for given brick of the volume + logMessages = getDiskLogs(volumeName, diskName, lineCount); + } + } catch (Exception e) { + return new LogMessageListResponse(new Status(e), null); + } + + return new LogMessageListResponse(Status.STATUS_SUCCESS, logMessages); + } public static void main(String[] args) { VolumesResource vr = new VolumesResource(); 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 4f99172d..47657c2a 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 @@ -39,7 +39,6 @@ import org.springframework.stereotype.Component; import com.gluster.storage.management.core.constants.CoreConstants; import com.gluster.storage.management.core.model.Status; -import com.gluster.storage.management.core.response.GenericResponse; import com.gluster.storage.management.core.utils.ProcessResult; import com.gluster.storage.management.core.utils.ProcessUtil; @@ -75,6 +74,7 @@ public class ServerUtil { * @param expectedClass Class of the object expected from script execution * @return Response from remote execution of the command */ + @SuppressWarnings("rawtypes") public Object executeOnServer(boolean runInForeground, String serverName, String commandWithArgs, Class expectedClass) { StringBuffer output = new StringBuffer(); try { @@ -114,6 +114,7 @@ public class ServerUtil { * class Status. If that also fails, a status object with exception message is created and returned. * @return Object of given expected class, or a status object in case first unmarshalling fails. */ + @SuppressWarnings("rawtypes") private Object unmarshal(Class expectedClass, String input, boolean tryStatusOnFailure) { try { // create JAXB context and instantiate marshaller -- cgit