Skip to content

Commit

Permalink
Merge pull request #5 from diegopacheco/dev
Browse files Browse the repository at this point in the history
Added Telemetry mode and some fixes.
  • Loading branch information
diegopacheco authored Oct 20, 2016
2 parents f462d6f + e9b74f7 commit 2fd0903
Show file tree
Hide file tree
Showing 12 changed files with 236 additions and 17 deletions.
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Dynomite Cluster Checker checks if a Dynomite cluster is working properly via Dy
* Check Node Fail over
* Check Whole Cluster connectivity and Seeds
* REST exposure for the report: http://localhost:7766/dynomite-cluster-checker/check?seeds="sd1|sd2|sd3..."
* Telemetry Mode: Most of people use solutions like Magios, Sensu, Zabbix, Prometheus, SignalFx and many other - This returns 0 for TRUE and 1 for FALSe or errros. So you can build lerts on top of the result json.

## TODO

Expand Down Expand Up @@ -212,6 +213,26 @@ All Seeds Cluster Failover test: FAIL: PoolOfflineException: [host=Host [hostnam

**** END DYNOMITE CLUSTER CHECKER ****

#
# 6. Telemetry Mode (i.e: seeds=seed1|seed2|seed3&telemetry=true)
#
curl "http://localhost:7766/dynomite-cluster-checker/check?seeds=127.0.0.1:rack1:local-dc:8101:1|127.0.0.22:rack2:local-dc:8101:2|127.0.0.13:rack1:local-dc:8101:1&telemetry=true"
{
"failoverStatus": "0",
"badNodes": 2,
"nodesReport": [
{
"server": "127.0.0.1",
"seeds": "[127.0.0.1:rack1:local-dc:8101:1]",
"insertTime": "1",
"getTime": "2",
"insertError": "0",
"getError": "0",
"consistency": "0"
}
]
}

```

You Can pass Muliples nodes. If you send mroe than One node we will check for the nodes data replication consistency.<BR>
Expand Down
3 changes: 3 additions & 0 deletions dynomite-cluster-checker/.classpath
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
<classpathentry kind="src" path="src/main/resources"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER" exported="true"/>
<classpathentry sourcepath="/home/diego/.gradle/caches/modules-2/files-2.1/javax.servlet/servlet-api/2.5/21599814ad9a605b86f3e6381571beccd861a32/servlet-api-2.5-sources.jar" kind="lib" path="/home/diego/.gradle/caches/modules-2/files-2.1/javax.servlet/servlet-api/2.5/5959582d97d8b61f4d154ca9e495aafd16726e34/servlet-api-2.5.jar" exported="true"/>
<classpathentry sourcepath="/home/diego/.gradle/caches/modules-2/files-2.1/org.apache.commons/commons-lang3/3.4/b49dafc9cfef24c356827f322e773e7c26725dd2/commons-lang3-3.4-sources.jar" kind="lib" path="/home/diego/.gradle/caches/modules-2/files-2.1/org.apache.commons/commons-lang3/3.4/5fe28b9518e58819180a43a850fbc0dd24b7c050/commons-lang3-3.4.jar" exported="true"/>
<classpathentry sourcepath="/home/diego/.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-simple/1.7.21/58eb8609a8f14e5bbf4d260ce5f364724079227/slf4j-simple-1.7.21-sources.jar" kind="lib" path="/home/diego/.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-simple/1.7.21/be4b3c560a37e69b6c58278116740db28832232c/slf4j-simple-1.7.21.jar" exported="true"/>
<classpathentry sourcepath="/home/diego/.gradle/caches/modules-2/files-2.1/com.netflix.dyno/dyno-jedis/1.4.7/7a9b9fd04d7b2d59c59dae14fa9536463de3a2d1/dyno-jedis-1.4.7-sources.jar" kind="lib" path="/home/diego/.gradle/caches/modules-2/files-2.1/com.netflix.dyno/dyno-jedis/1.4.7/57d8d80d76ead546b0570ee80108d5fdf4a3816c/dyno-jedis-1.4.7.jar" exported="true"/>
<classpathentry sourcepath="/home/diego/.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-api/1.7.21/f285ac123f201fb4b028bac556928d7cf527ef48/slf4j-api-1.7.21-sources.jar" kind="lib" path="/home/diego/.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-api/1.7.21/139535a69a4239db087de9bab0bee568bf8e0b70/slf4j-api-1.7.21.jar" exported="true"/>
<classpathentry sourcepath="/home/diego/.gradle/caches/modules-2/files-2.1/joda-time/joda-time/2.3/ecd8588d8ce0963eb443de31d5fea29e3205f160/joda-time-2.3-sources.jar" kind="lib" path="/home/diego/.gradle/caches/modules-2/files-2.1/joda-time/joda-time/2.3/56498efd17752898cfcc3868c1b6211a07b12b8f/joda-time-2.3.jar" exported="true"/>
<classpathentry sourcepath="/home/diego/.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-log4j12/1.7.21/16b1333786ea93d16bff6fb0f5e3b82716d1b008/slf4j-log4j12-1.7.21-sources.jar" kind="lib" path="/home/diego/.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-log4j12/1.7.21/7238b064d1aba20da2ac03217d700d91e02460fa/slf4j-log4j12-1.7.21.jar" exported="true"/>
<classpathentry sourcepath="/home/diego/.gradle/caches/modules-2/files-2.1/com.googlecode.json-simple/json-simple/1.1/19c6d8dee6803c520d855ff7e8a8c3d97f1271ec/json-simple-1.1-sources.jar" kind="lib" path="/home/diego/.gradle/caches/modules-2/files-2.1/com.googlecode.json-simple/json-simple/1.1/5e303a03d04e6788dddfa3655272580ae0fc13bb/json-simple-1.1.jar" exported="true"/>
Expand Down
2 changes: 2 additions & 0 deletions dynomite-cluster-checker/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
/bin/
.idea
dynomite-cluster-checker.iml
3 changes: 2 additions & 1 deletion dynomite-cluster-checker/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,10 @@ eclipse {
dependencies {
compile([
'javax.servlet:servlet-api:2.5',
'org.apache.commons:commons-lang3:3.4',
'org.slf4j:slf4j-simple:1.7.21'
])

testCompile('junit:junit:4.11')
compile('com.netflix.dyno:dyno-jedis:1.4.7'){
exclude group: 'org.slf4j', module: 'slf4j-api'
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,34 @@ public String toPrettyJson(){
" }";
}

public String toPrettyTelemetryJson(){
return " {\r\n" +
pritIfNotNull(" \"server\":\"" + server + "\",\r\n",server) +
pritIfNotNull(" \"seeds\":\"" + seeds + "\",\r\n",seeds) +
pritIfNotNull(" \"insertTime\":\"" + getInsertTime(insertTime) + "\",\r\n",insertTime) +
pritIfNotNull(" \"getTime\":\"" + new Double(getTime.replace("ms", "").trim()).intValue() + "\",\r\n",getTime) +
pritIfNotNull(" \"insertError\":\"" + resolveErrorTelemetry(insertError) + "\",\r\n",resolveErrorTelemetry(insertError)) +
pritIfNotNull(" \"getError\":\"" + resolveErrorTelemetry(getError) + "\",\r\n",resolveErrorTelemetry(getError)) +
" \"consistency\":\"" + resolveBoolean(consistency) + "\"\r\n" +
" }";
}

private int getInsertTime(String insertTime) {
return (insertTime == null) ? 0 : new Double(insertTime.replace("ms", "").trim()).intValue();
}

private int resolveBoolean(boolean bol){
return (bol) ? 0 : 1;
}

private String pritIfNotNull(String msg,String field){
return ("".equals(field) || null == field) ? "" : msg;
}

private String resolveErrorTelemetry(String field){
return ("".equals(field) || null == field) ? "0" : "1";
}

@Override
public String toString() {
return toPrettyJson();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ public class DynomiteClusterCheckerMain {

public static void main(String[] args){
DynomiteClusterCheckerMain dcc = new DynomiteClusterCheckerMain();
dcc.run(args[0]);
dcc.run(args[0],false);
}

public String run(String seeds){
public String run(String seeds,boolean telemetryMode){

resultReport.setNodesReport(new ArrayList<>());
CheckerResponse checkerResponse = new CheckerResponse();
Expand All @@ -43,6 +43,7 @@ public String run(String seeds){
badNodes.removeAll(validNodes);

if(badNodes!=null && badNodes.size() >= 1 ){
resultReport.setBadNodes(badNodes);
bufferedLogInfo("BAD NODES:");
for(DynomiteNodeInfo node: badNodes){
bufferedLogInfo(" " + node.toString());
Expand Down Expand Up @@ -80,8 +81,8 @@ public String run(String seeds){

}

bufferedLogInfo("4. Shwoing Results as JSON... ");
String jsonResult = ListJsonPrinter.print(resultReport);
bufferedLogInfo("4. Results as JSON... ");
String jsonResult = (telemetryMode) ? ListJsonPrinter.printTelemetry(resultReport) : ListJsonPrinter.print(resultReport);
bufferedLogInfo(jsonResult);
bufferedLogInfo("**** END DYNOMITE CLUSTER CHECKER ****");
bufferedLogPrint();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,52 @@

import java.util.List;

import com.github.diegopacheco.dynomite.cluster.checker.parser.DynomiteNodeInfo;
import com.google.common.collect.ImmutableList;

public class ResultReport {

private String failoverStatus;
private List<CheckerResponse> nodesReport;
private List<DynomiteNodeInfo> badNodes;

public ResultReport() {}

public String getFailoverStatus() {
return failoverStatus;
}
public int getFailoverStatusTelemetry() {
return "ok".toUpperCase().equals(failoverStatus) ? 0 : 1;
}

public void setFailoverStatus(String failoverStatus) {
this.failoverStatus = failoverStatus;
}

public List<CheckerResponse> getNodesReport() {
return nodesReport;
}

public int getBadNodesTelemetry() {
return (badNodes==null) ? 0 : badNodes.size();
}

public void setNodesReport(List<CheckerResponse> nodesReport) {
this.nodesReport = nodesReport;
}


@Override
public String toString() {
return "ResultReport [failoverStatus=" + failoverStatus + ", nodesReport=" + nodesReport + "]";
public List<DynomiteNodeInfo> getBadNodes() {
return badNodes;
}
public void setBadNodes(List<DynomiteNodeInfo> badNodes) {
this.badNodes = ImmutableList.copyOf(badNodes);
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((badNodes == null) ? 0 : badNodes.hashCode());
result = prime * result + ((failoverStatus == null) ? 0 : failoverStatus.hashCode());
result = prime * result + ((nodesReport == null) ? 0 : nodesReport.hashCode());
return result;
Expand All @@ -47,6 +62,11 @@ public boolean equals(Object obj) {
if (getClass() != obj.getClass())
return false;
ResultReport other = (ResultReport) obj;
if (badNodes == null) {
if (other.badNodes != null)
return false;
} else if (!badNodes.equals(other.badNodes))
return false;
if (failoverStatus == null) {
if (other.failoverStatus != null)
return false;
Expand All @@ -59,5 +79,10 @@ public boolean equals(Object obj) {
return false;
return true;
}


@Override
public String toString() {
return "ResultReport [failoverStatus=" + failoverStatus + ", nodesReport=" + nodesReport + ", badNodes="
+ badNodes + "]";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
Expand All @@ -21,18 +22,41 @@ public class RestServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter out = resp.getWriter();
try{
String seeds = req.getParameter("seeds").toString();
logger.info("Checking seeds: " + seeds);
String seeds = req.getParameter("seeds");
if (seeds==null){
out.write("{ \"Error\": \"Abort! seeds cannot be nuul!\" }");
return;
}

DynomiteClusterCheckerMain dcc = new DynomiteClusterCheckerMain();
String json = dcc.run(seeds);
boolean ShouldRunTelemetryMode = resolveTelemetryMode(req.getParameterValues("telemetry"));
logArgs(req);

String json = dcc.run(seeds, ShouldRunTelemetryMode);
out.write(json);
}catch(Exception e){
logger.error(e);
out.write("{ \"Error\": " + e.toString() + " }");
logger.error(e);
out.write("{ \"Error\": \"" + e.toString() + " - " + org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e) + "\" }");
}finally {
out.close();
}
}

@SuppressWarnings("unchecked")
private void logArgs(HttpServletRequest req){
logger.info("Checking seeds: " + req.getParameter("seeds"));
logger.info("TELEMETRY mode: " + req.getParameterValues("telemetry"));

Enumeration<String> parameterNames = req.getParameterNames();
while(parameterNames.hasMoreElements()){
String paramName = parameterNames.nextElement();
logger.info("Other parameter: " + paramName);
}
}

private boolean resolveTelemetryMode(String telemetry[]){
if (telemetry==null) return false;
return ("true".equals(telemetry[0])) ? true : false;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@
*/
public interface JsonPrinter {
public String toPrettyJson();
public String toPrettyTelemetryJson();
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package com.github.diegopacheco.dynomite.cluster.checker.util;

import java.util.List;
import java.util.stream.Collectors;

import com.github.diegopacheco.dynomite.cluster.checker.ResultReport;
import com.github.diegopacheco.dynomite.cluster.checker.parser.DynomiteNodeInfo;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;

/**
* Pritns a list of JsonPrinter in Json.
Expand All @@ -15,19 +19,63 @@ public class ListJsonPrinter {

public static String print(ResultReport rr){
List<? extends JsonPrinter> list = rr.getNodesReport();
if (list.size()==1) return list.get(0).toPrettyJson();

StringBuffer sb = new StringBuffer("{\n\r");
sb.append(" \"failoverStatus\": \"" + rr.getFailoverStatus() + "\",\n\r");

if(rr.getBadNodes()!=null && rr.getBadNodes().size() >= 1 ){
sb.append(" \"badNodes\": [");
int i = 0;
for(DynomiteNodeInfo node: rr.getBadNodes()){
sb.append("\"" + node.toString() + "\"");
if ((i+1) < rr.getBadNodes().size())
sb.append(", ");
i++;
}
sb.append(" ], \n\r");
}else{
sb.append(" \"badNodes\": [], \n\r");
}

sb.append(" \"nodesReport\":\n\r");
Object[] array = list.toArray();
sb.append("[\n\r");
for(int i=0;i<array.length;i++){
sb.append( ((JsonPrinter)array[i]).toPrettyJson() + ( (i+1<array.length) ? ",\n\r" : "\n\r") );
sb.append( ((JsonPrinter)array[i]).toPrettyJson() + resolveComma(array,i) );
}
sb.append("]\n\r");
sb.append("}\n\r");
return sb.toString();
}

public static String printTelemetry(ResultReport rr){
List<? extends JsonPrinter> list = rr.getNodesReport();

StringBuffer sb = new StringBuffer("{\n\r");
sb.append(" \"failoverStatus\": \"" + rr.getFailoverStatusTelemetry() + "\",\n\r");

if (areBadNodes(rr.getBadNodesTelemetry()))
sb.append(" \"badNodeNames\": \""+ String.join(",", rr.getBadNodes().stream().map(badNode -> badNode.getServer()).collect(Collectors.toList())) + "\", \n\r");

sb.append(" \"badNodes\": "+ rr.getBadNodesTelemetry() + ", \n\r");

sb.append(" \"nodesReport\":\n\r");
Object[] array = list.toArray();
sb.append("[\n\r");
for(int i=0;i<array.length;i++){
sb.append( ((JsonPrinter)array[i]).toPrettyTelemetryJson() + resolveComma(array,i) );
}
sb.append("]\n\r");
sb.append("}\n\r");
return sb.toString();
}

private static boolean areBadNodes(int badNodes) {
return badNodes > 0;
}

private static String resolveComma(Object[] array,int i){
return ( (i+1<array.length) ? ",\n\r" : "\n\r");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.github.diegopacheco.dynomite.cluster.checker;

import org.junit.Test;
import static org.junit.Assert.assertTrue;

public class CheckerResponseTest {

@Test
public void shouldNotBreakWhenThereIsNoInsertTime() {
CheckerResponse checkerResponse = new CheckerResponse("172.28.198.18:8102:rack1:default_dc:100", null, "0", false, "localhost");
String content = checkerResponse.toPrettyTelemetryJson();
assertTrue(content.contains("\"server\":\"localhost\""));
assertTrue(content.contains("\"seeds\":\"172.28.198.18:8102:rack1:default_dc:100\""));
assertTrue(content.contains("\"getTime\":\"0\""));
assertTrue(content.contains("\"insertError\":\"0\""));
assertTrue(content.contains("\"getError\":\"0\""));
assertTrue(content.contains("\"consistency\":\"1\""));
}

}

Loading

0 comments on commit 2fd0903

Please sign in to comment.