-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add health report endpoint. Add HealthReporterService. * Add status page. * Fix CrossOrigin settigns for health report endpoint. Fix status page. * Remove excessive cache operations.
- Loading branch information
1 parent
80f7938
commit b4b352e
Showing
5 changed files
with
241 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<script src="https://code.jquery.com/jquery-1.11.1.min.js"></script> | ||
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css"> | ||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.0/js/bootstrap.min.js"></script> | ||
</head> | ||
<link href="https://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css" rel="stylesheet" type="text/css" /> | ||
<script src="https://code.jquery.com/jquery.min.js"></script> | ||
|
||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script> | ||
<div class="container"> | ||
<div class="row"> | ||
<div class="col-md-12"> | ||
<h1>Extender Status Page</h1> | ||
</div> | ||
</div> | ||
<div class="row clearfix"> | ||
<div id="stage" class="col-md-12 column"> | ||
<h2 class="panel-title">Stage server</h2> | ||
<div id="statusPanel" class="panel"> | ||
<div class="panel-heading"> | ||
<h3 id="statusTitle" class="panel-title"> | ||
<!-- Not All Systems Operational --> | ||
</h3> | ||
</div> | ||
</div> | ||
<div class="row clearfix"> | ||
<div class="col-md-6 column"> | ||
<div id="list-1" class="list-group"></div> | ||
</div> | ||
<div class="col-md-6 column"> | ||
<div id="list-2" class="list-group"></div> | ||
</div> | ||
</div> | ||
</div> | ||
|
||
<div id="prod" class="col-md-12 column"> | ||
<h2 class="panel-title">Production server</h2> | ||
<div id="statusPanel" class="panel"> | ||
<div class="panel-heading"> | ||
<h3 id="statusTitle" class="panel-title"> | ||
<!-- Not All Systems Operational --> | ||
</h3> | ||
</div> | ||
</div> | ||
<div class="row clearfix"> | ||
<div class="col-md-6 column"> | ||
<div id="list-1" class="list-group"></div> | ||
</div> | ||
<div class="col-md-6 column"> | ||
<div id="list-2" class="list-group"></div> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
<script type="text/javascript"> | ||
const OperationalStatus = "Operational"; | ||
const UnreachableStatus = "Unreachable"; | ||
const NotFullyOperationalStatus = "NotFullyOperational"; | ||
function addBlock(id, status, parent_block) { | ||
var top_block = $("<div/>"); | ||
top_block.addClass("list-group-item"); | ||
|
||
var heading = $("<h4/>"); | ||
heading.addClass("list-group-item-heading"); | ||
heading.text(id); | ||
heading.appendTo(top_block); | ||
|
||
var status_block = $("<p/>"); | ||
status_block.addClass("list-group-item-text"); | ||
|
||
var inner_span = $("<span/>"); | ||
inner_span.addClass("label"); | ||
if (status == OperationalStatus) { | ||
inner_span.addClass("label-success"); | ||
} else if (status == UnreachableStatus) { | ||
inner_span.addClass("label-danger"); | ||
} else { | ||
inner_span.addClass("label-warning"); | ||
} | ||
inner_span.text(status); | ||
|
||
inner_span.appendTo(top_block); | ||
|
||
top_block.appendTo(parent_block); | ||
} | ||
function handleResponse(response, rootId) { | ||
var totalFullyOperatedPlatforms, totalUnreachablePlatforms = 0; | ||
var parent_block_1 = $(rootId).find("#list-1"); | ||
var parent_block_2 = $(rootId).find("#list-2"); | ||
var idx = 0; | ||
for (var key in response) { | ||
addBlock(key, response[key], idx % 2 == 0 ? parent_block_1 : parent_block_2); | ||
if (response[key] == OperationalStatus) { | ||
totalFullyOperatedPlatforms++; | ||
} else if (response[key] == UnreachableStatus) { | ||
totalUnreachablePlatforms++; | ||
} | ||
idx++; | ||
} | ||
if (totalUnreachablePlatforms == idx) { | ||
$(rootId).find("#statusPanel").addClass("panel-danger"); | ||
$(rootId).find("#statusTitle").text(UnreachableStatus); | ||
} else if (totalFullyOperatedPlatforms == idx) { | ||
$(rootId).find("#statusPanel").addClass("panel-success"); | ||
$(rootId).find("#statusTitle").text(OperationalStatus); | ||
} else { | ||
$(rootId).find("#statusPanel").addClass("panel-warning"); | ||
$(rootId).find("#statusTitle").text(NotFullyOperationalStatus); | ||
} | ||
} | ||
function handleError(err, rootId) { | ||
$(rootId).find("#statusPanel").addClass("panel-danger"); | ||
$(rootId).find("#statusTitle").text(UnreachableStatus); | ||
} | ||
|
||
var r = new XMLHttpRequest(); | ||
r.open("GET", "https://build-stage.defold.com/health_report"); | ||
r.onload = function(response) { | ||
handleResponse(JSON.parse(response.target.responseText), "#stage"); | ||
} | ||
r.onerror = function(err) { | ||
handleError(err, "#stage"); | ||
} | ||
r.send(null); | ||
|
||
var r = new XMLHttpRequest(); | ||
r.open("GET", "https://build.defold.com/health_report"); | ||
r.onload = function(response) { | ||
handleResponse(JSON.parse(response.target.responseText), "#prod"); | ||
} | ||
r.onerror = function(err) { | ||
handleError(err, "#prod"); | ||
} | ||
r.send(null); | ||
</script> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
86 changes: 86 additions & 0 deletions
86
server/src/main/java/com/defold/extender/services/HealthReporterService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
package com.defold.extender.services; | ||
|
||
import java.util.Collections; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
import org.apache.http.HttpResponse; | ||
import org.apache.http.client.HttpClient; | ||
import org.apache.http.client.methods.HttpGet; | ||
import org.apache.http.impl.client.HttpClientBuilder; | ||
import org.apache.http.util.EntityUtils; | ||
import org.json.simple.JSONObject; | ||
import org.json.simple.parser.JSONParser; | ||
import org.springframework.stereotype.Service; | ||
|
||
@Service | ||
public class HealthReporterService { | ||
public enum OperationalStatus { | ||
Unreachable, | ||
NotFullyOperational, | ||
Operational | ||
} | ||
|
||
public HealthReporterService() { | ||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
public String collectHealthReport(boolean isRemoteBuildEnabled, Map<String, String> remoteBuilderPlatformMappings) { | ||
if (isRemoteBuildEnabled) { | ||
// we collect information by platform. If one of the builder is unreachable - set | ||
Map<String, OperationalStatus> platformOperationalStatus = new HashMap<>(); | ||
JSONObject result = new JSONObject(); | ||
JSONParser parser = new JSONParser(); | ||
final HttpClient client = HttpClientBuilder.create().build(); | ||
for (Map.Entry<String, String> entry : remoteBuilderPlatformMappings.entrySet()) { | ||
final String healthUrl = String.format("%s/health_report", entry.getValue()); | ||
final HttpGet request = new HttpGet(healthUrl); | ||
String platform = getPlatform(entry.getKey()); | ||
try { | ||
HttpResponse response = client.execute(request); | ||
if (response.getStatusLine().getStatusCode() == org.apache.http.HttpStatus.SC_OK) { | ||
JSONObject responseBody = (JSONObject)parser.parse(EntityUtils.toString(response.getEntity())); | ||
if (responseBody.containsKey("status") | ||
&& OperationalStatus.valueOf((String)responseBody.get("status")) == OperationalStatus.Operational) { | ||
updateOperationalStatus(platformOperationalStatus, platform, true); | ||
} else { | ||
updateOperationalStatus(platformOperationalStatus, platform, false); | ||
} | ||
} else { | ||
updateOperationalStatus(platformOperationalStatus, platform, false); | ||
} | ||
} catch(Exception exc) { | ||
updateOperationalStatus(platformOperationalStatus, platform, false); | ||
} | ||
} | ||
|
||
for (Map.Entry<String, OperationalStatus> entry : platformOperationalStatus.entrySet()) { | ||
result.put(entry.getKey(), entry.getValue().toString()); | ||
} | ||
return result.toJSONString(); | ||
} else { | ||
return JSONObject.toJSONString(Collections.singletonMap("status", OperationalStatus.Operational.toString())); | ||
} | ||
} | ||
|
||
private String getPlatform(String hostId) { | ||
return hostId.split("-")[0]; | ||
} | ||
|
||
private void updateOperationalStatus(Map<String, OperationalStatus> statuses, String platform, boolean isBuilderUp) { | ||
if (statuses.containsKey(platform)) { | ||
OperationalStatus prevStatus = (OperationalStatus)statuses.get(platform); | ||
if (isBuilderUp) { | ||
if (prevStatus == OperationalStatus.Unreachable) { | ||
statuses.put(platform, OperationalStatus.NotFullyOperational); | ||
} | ||
} else { | ||
if (prevStatus == OperationalStatus.Operational) { | ||
statuses.put(platform, OperationalStatus.NotFullyOperational); | ||
} | ||
} | ||
} else { | ||
statuses.put(platform, isBuilderUp ? OperationalStatus.Operational : OperationalStatus.Unreachable); | ||
} | ||
} | ||
} |