740 lines
23 KiB
HTML
740 lines
23 KiB
HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="en-US">
|
|
<head profile="http://gmpg.org/xfn/11">
|
|
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
|
|
|
|
<title>Shaker | The distributed data-plane testing tool for OpenStack</title>
|
|
|
|
<!-- LIBS -->
|
|
|
|
<script type="application/javascript"
|
|
src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
|
<script type="application/javascript"
|
|
src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.2/jquery-ui.min.js"></script>
|
|
<script type="application/javascript"
|
|
src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/js/bootstrap.js"></script>
|
|
<script type="text/javascript"
|
|
src="https://cdn.datatables.net/1.10.2/js/jquery.dataTables.min.js"></script>
|
|
<script type="text/javascript"
|
|
src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/3.0.1/handlebars.min.js"></script>
|
|
<script type="application/javascript"
|
|
src="https://cdnjs.cloudflare.com/ajax/libs/js-yaml/3.2.7/js-yaml.min.js"></script>
|
|
<script type="application/javascript"
|
|
src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
|
|
<script type="application/javascript"
|
|
src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.10/c3.js"></script>
|
|
|
|
<!-- STYLES -->
|
|
|
|
<link rel="stylesheet"
|
|
href="https://maxcdn.bootstrapcdn.com/bootswatch/3.3.4/simplex/bootstrap.min.css">
|
|
<link rel=stylesheet type=text/css
|
|
href="https://cdn.datatables.net/1.10.2/css/jquery.dataTables.min.css">
|
|
<link rel=stylesheet type=text/css
|
|
href="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.10/c3.css">
|
|
<link rel='stylesheet' type='text/css'
|
|
href='http://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic&subset=latin,cyrillic'>
|
|
|
|
<script type="application/javascript">
|
|
var report = [[[ report | json]]];
|
|
</script>
|
|
|
|
<script type="text/javascript">
|
|
"use strict";
|
|
|
|
$(function () {
|
|
|
|
var fields = ["scenario", "test", "concurrency", "node", "agent"];
|
|
var state = {
|
|
scenario: "",
|
|
test: "",
|
|
concurrency: "",
|
|
node: "",
|
|
agent: ""
|
|
};
|
|
var tablePageSize = 10;
|
|
|
|
// compiled templates
|
|
var scenario_source_template = Handlebars.compile($("#scenario_source_template").html());
|
|
var test_specification_template = Handlebars.compile($("#test_specification_template").html());
|
|
var agents_table_template = Handlebars.compile($("#agents_table_template").html());
|
|
var records_table_template = Handlebars.compile($("#records_table_template").html());
|
|
var executor_template = Handlebars.compile($("#executor_template").html());
|
|
var concurrency_summary_template = Handlebars.compile($("#concurrency_summary_template").html());
|
|
var test_summary_template = Handlebars.compile($("#test_summary_template").html());
|
|
var sla_table_template = Handlebars.compile($("#sla_table_template").html());
|
|
var errors_template = Handlebars.compile($("#errors_template").html());
|
|
|
|
function concatenate(strings) {
|
|
// returns strings concatenated via comma (like join() but omits empty strings)
|
|
var f = false;
|
|
var result = "";
|
|
$.each(strings, function (_i, string) {
|
|
if (string.length > 0) {
|
|
if (f) result += ", ";
|
|
result += string;
|
|
f = true;
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
|
|
function initSingleSelector(name, values) {
|
|
var selectorId = "#" + name + "_selector";
|
|
|
|
var selector_inst = $(selectorId);
|
|
selector_inst.empty();
|
|
selector_inst.append($("<option>", {
|
|
style: "font-style: italic; text-decoration: underline;",
|
|
value: "",
|
|
text: selector_inst.data('placeholder')
|
|
}));
|
|
|
|
$.each(values, function (key, item) {
|
|
selector_inst.append($('<option>', {
|
|
value: item, //(key + 1),
|
|
text: item
|
|
}));
|
|
});
|
|
|
|
selector_inst.val(state[name]);
|
|
|
|
selector_inst.
|
|
on("change", function (e) {
|
|
state[name] = this.value;
|
|
|
|
// convert state -> url
|
|
var tokens = [];
|
|
$.each(fields.sort(), function (i, field) {
|
|
if (state[field] != "") {
|
|
tokens.push(field + "=" + state[field]);
|
|
}
|
|
});
|
|
window.location.href = "#" + tokens.join(":");
|
|
});
|
|
}
|
|
|
|
function getFieldValues(field, records) {
|
|
var values_set = {};
|
|
|
|
$.each(records, function (j, record) {
|
|
if (record[field]) {
|
|
values_set["" + record[field]] = true;
|
|
}
|
|
});
|
|
|
|
return $.map(values_set, function (_i, value) {
|
|
return value;
|
|
}).sort();
|
|
}
|
|
|
|
function updateSelectors() {
|
|
$.each(fields, function (i, field) {
|
|
var values = getFieldValues(field, filterRecords(report.records, null, field));
|
|
console.log(values);
|
|
initSingleSelector(field, values);
|
|
});
|
|
}
|
|
|
|
function filterRecords(records, type, except_field) {
|
|
var res = [];
|
|
$.each(records, function(_i, record){
|
|
if (!type || typeof type === 'undefined' || record.type == type) {
|
|
var flag = true;
|
|
$.each(state, function (key, value) {
|
|
if (key != except_field && value) {
|
|
flag &= record[key] == value;
|
|
}
|
|
});
|
|
if (flag) {
|
|
res.push(record);
|
|
}
|
|
}
|
|
});
|
|
return res;
|
|
}
|
|
|
|
function getAgentsByIds(agent_ids) {
|
|
var agents = [];
|
|
$.each(agent_ids, function(agent_id){
|
|
agents.push(report.agents[agent_id]);
|
|
});
|
|
return agents;
|
|
}
|
|
|
|
/* Template Rendering Funcs */
|
|
|
|
function showScenarioSource(contentArea, scenario) {
|
|
contentArea.append(scenario_source_template(
|
|
{data: jsyaml.safeDump(scenario)}));
|
|
}
|
|
|
|
function showTestSpecification(contentArea, test) {
|
|
contentArea.append(test_specification_template(
|
|
{data: jsyaml.safeDump(test)}
|
|
))
|
|
}
|
|
|
|
function showAgentRecord(contentArea, record) {
|
|
var chart_id = "chart_" + Math.round(Math.random() * 10000);
|
|
var ext_options = {
|
|
command_yaml: jsyaml.safeDump(record["command"]),
|
|
chart_id: chart_id};
|
|
if (record["stats"]) {
|
|
ext_options["stats_yaml"] = jsyaml.safeDump(record["stats"]);
|
|
}
|
|
if ((record["start"]) && (record["finish"])) {
|
|
ext_options["time_info"] = jsyaml.safeDump({
|
|
"start": new Date(record["start"] * 1000).toISOString(),
|
|
"finish": new Date(record["finish"] * 1000).toISOString()
|
|
});
|
|
}
|
|
contentArea.append(executor_template(
|
|
{record: $.extend({}, record, ext_options)}
|
|
));
|
|
if (record["samples"]) {
|
|
var meta = record["meta"];
|
|
var axes = [];
|
|
axes[meta[1][0]] = 'y';
|
|
var axis = {
|
|
x: {label: concatenate(meta[0])},
|
|
y: {label: concatenate(meta[1]), min: 0}
|
|
};
|
|
if (meta.length > 2) {
|
|
axes[meta[2][0]] = 'y2';
|
|
axis['y2'] = {label: concatenate(meta[2]), min: 0, show: true}
|
|
}
|
|
|
|
var chart = [];
|
|
$.each(meta, function(_i, meta_item){ // row titles
|
|
chart.push([meta_item[0]]);
|
|
});
|
|
var samples = record["samples"];
|
|
for (var i=0; i < samples.length; i++) {
|
|
var point = samples[i];
|
|
for (var j=0; j < point.length; j++) {
|
|
chart[j].push(point[j]);
|
|
}
|
|
}
|
|
|
|
c3.generate({
|
|
bindto: "#" + chart_id,
|
|
data: {
|
|
x: 'time',
|
|
columns: chart,
|
|
axes: axes
|
|
},
|
|
axis: axis
|
|
});
|
|
}
|
|
}
|
|
|
|
function showConcurrencySummary(contentArea, record) {
|
|
var chart_id = "chart_" + Math.round(Math.random() * 10000);
|
|
var node_chart_id = "node_chart_" + Math.round(Math.random() * 10000);
|
|
var ext_options = { chart_id: chart_id, node_chart_id: node_chart_id };
|
|
if (record["stats"]) {
|
|
ext_options["stats_yaml"] = jsyaml.safeDump(record["stats"]);
|
|
}
|
|
console.log(record);
|
|
contentArea.append(concurrency_summary_template(
|
|
{record: $.extend({}, record, ext_options)}
|
|
));
|
|
if (record["node_chart"]) {
|
|
c3.generate({
|
|
bindto: "#" + node_chart_id,
|
|
data: {
|
|
x: 'x',
|
|
columns: record["node_chart"],
|
|
type: 'step',
|
|
order: null
|
|
},
|
|
axis: {
|
|
x: { type: 'category' }
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
function showTestSummary(contentArea, record) {
|
|
console.log(record);
|
|
var chart_id = "chart_" + Math.round(Math.random() * 10000);
|
|
var ext_options = { chart_id: chart_id };
|
|
if (record["stats"]) {
|
|
ext_options["stats_yaml"] = jsyaml.safeDump(record["stats"]);
|
|
}
|
|
contentArea.append(test_summary_template(
|
|
{record: $.extend({}, record, ext_options)}
|
|
));
|
|
if (record["chart"]) {
|
|
var meta = record["meta"];
|
|
var axes = [];
|
|
axes[meta[1][0]] = 'y';
|
|
var axis = {
|
|
x: {label: concatenate(meta[0])},
|
|
y: {label: concatenate(meta[1]), min: 0}
|
|
};
|
|
if (meta.length > 2) {
|
|
axes[meta[2][0]] = 'y2';
|
|
axis['y2'] = {label: concatenate(meta[2]), min: 0, show: true}
|
|
}
|
|
|
|
c3.generate({
|
|
bindto: "#" + chart_id,
|
|
data: {
|
|
x: 'concurrency',
|
|
columns: record["chart"],
|
|
axes: axes
|
|
},
|
|
axis: axis
|
|
});
|
|
}
|
|
}
|
|
|
|
function showAgentsTable(contentArea, filteredRecords) {
|
|
var agent_ids = {};
|
|
$.each(filteredRecords, function(_i, record){
|
|
if (record.agent) {
|
|
agent_ids[record.agent] = true;
|
|
}
|
|
});
|
|
|
|
var agents = getAgentsByIds(agent_ids);
|
|
if (agents.length == 0) return;
|
|
|
|
// add slave agents
|
|
var slave_agent_ids = {};
|
|
$.each(agents, function(_i, agent){
|
|
if (agent.slave_id) {
|
|
slave_agent_ids[agent.slave_id] = true;
|
|
}
|
|
});
|
|
agents = $.merge(agents, getAgentsByIds(slave_agent_ids));
|
|
|
|
contentArea.append(agents_table_template({
|
|
agents: agents,
|
|
table_id: "agents_table"
|
|
}));
|
|
$("#agents_table").dataTable({
|
|
"autoWidth": true,
|
|
"paging": false,
|
|
"ordering": true,
|
|
"info": false
|
|
});
|
|
}
|
|
|
|
function makeURL(record, s) {
|
|
var extra = {};
|
|
extra[s] = record[s];
|
|
return "#" + $.map($.extend({}, state, extra), function (val, index) {
|
|
return val? (index + "=" + val) : null;
|
|
}).join(":")
|
|
}
|
|
|
|
function showRecordsTable(contentArea, filteredRecords) {
|
|
$.each(filteredRecords, function(_i, record) {
|
|
$.each(fields, function(_j, field){
|
|
if (record[field]) {
|
|
record[field + "_url"] = makeURL(record, field);
|
|
}
|
|
});
|
|
});
|
|
|
|
contentArea.append(records_table_template({
|
|
records: filteredRecords,
|
|
table_id: "records_table"
|
|
}));
|
|
$("#records_table").dataTable({
|
|
autoWidth: true,
|
|
paging: filteredRecords.length > tablePageSize,
|
|
ordering: true,
|
|
info: false,
|
|
searching: filteredRecords.length > tablePageSize
|
|
});
|
|
}
|
|
|
|
function showSlaTable(contentArea, records) {
|
|
if (records.length == 0) return;
|
|
|
|
contentArea.append(sla_table_template({
|
|
records: records,
|
|
table_id: "sla_table"
|
|
}));
|
|
$("#records_table").dataTable({
|
|
autoWidth: true,
|
|
paging: records.length > tablePageSize,
|
|
ordering: true,
|
|
info: false,
|
|
searching: records.length > tablePageSize
|
|
});
|
|
}
|
|
|
|
function showErrors(contentArea, records) {
|
|
if (records.length == 0) return;
|
|
|
|
contentArea.append(errors_template({
|
|
records: records,
|
|
table_id: "errors_list"
|
|
}));
|
|
}
|
|
|
|
/* Update cycle */
|
|
|
|
function update() {
|
|
var filteredRecords = filterRecords(report.records);
|
|
console.log(filteredRecords);
|
|
var slaRecords = [];
|
|
var errorRecords = [];
|
|
$.each(filterRecords(report.records), function(_i, record) {
|
|
if (record["sla_info"]) {
|
|
slaRecords.push(record);
|
|
}
|
|
if (record["is_status_error"]) {
|
|
errorRecords.push(record);
|
|
}
|
|
});
|
|
|
|
var contentArea = $("#content_area");
|
|
contentArea.empty();
|
|
|
|
updateSelectors();
|
|
|
|
showRecordsTable(contentArea, filteredRecords);
|
|
showSlaTable(contentArea, slaRecords);
|
|
showErrors(contentArea, errorRecords);
|
|
|
|
if (state["scenario"] != "" && state["test"] != "" &&
|
|
state["concurrency"] != "" &&
|
|
state["agent"] != "") {
|
|
showAgentRecord(contentArea, filteredRecords[0]);
|
|
}
|
|
if (state["scenario"] != "" && state["test"] != "" &&
|
|
state["concurrency"] != "" && state["node"] == "" &&
|
|
state["agent"] == "") {
|
|
var agg_recs = filterRecords(report.records, "concurrency");
|
|
if (agg_recs.length > 0) {
|
|
showConcurrencySummary(contentArea, agg_recs[0]);
|
|
}
|
|
}
|
|
if (state["scenario"] != "" && state["test"] != "" &&
|
|
state["concurrency"] == "" && state["node"] == "" &&
|
|
state["agent"] == "") {
|
|
var test_recs = filterRecords(report.records, "test");
|
|
if (test_recs.length > 0) {
|
|
showTestSummary(contentArea, test_recs[0]);
|
|
}
|
|
}
|
|
if (state["test"] != "") {
|
|
showTestSpecification(contentArea, report.tests[state["test"]]);
|
|
}
|
|
if (state["agent"] == "") {
|
|
showAgentsTable(contentArea, filteredRecords);
|
|
}
|
|
if (state["scenario"] != "") {
|
|
showScenarioSource(contentArea, report.scenarios[state["scenario"]]);
|
|
}
|
|
}
|
|
|
|
function parseUrlToState() {
|
|
var hashUrl = window.location.hash.substr(1);
|
|
|
|
$.each(hashUrl.split(":"), function (_i, pair) {
|
|
var kv = pair.split("=");
|
|
if (kv.length == 2) {
|
|
state[kv[0]] = decodeURIComponent(kv[1]);
|
|
}
|
|
});
|
|
}
|
|
|
|
// entry-point
|
|
parseUrlToState();
|
|
console.log(state);
|
|
|
|
// change the status of tests that have sla failures
|
|
// to "fail", only if they were previously marked "ok"
|
|
$.each(report.sla, function(_i, sla) {
|
|
if (sla.state == "FAIL" && report.records[sla.record].status == "ok") {
|
|
report.records[sla.record].status = "fail";
|
|
}
|
|
});
|
|
// pre-process records
|
|
$.each(report.records, function(_i, record) {
|
|
if (record.status) {
|
|
record["is_status_ok"] = record.status == "ok";
|
|
record["is_status_lost"] = record.status == "lost";
|
|
record["is_status_interrupted"] = record.status == "interrupted";
|
|
record["is_status_error"] = record.status == "error";
|
|
record["is_status_fail"] = record.status == "fail";
|
|
}
|
|
});
|
|
|
|
// auto-select filters with 1 option
|
|
$.each(fields, function(_i, field) {
|
|
var values = getFieldValues(field, report.records);
|
|
if (values.length == 1) {
|
|
state[field] = values[0];
|
|
}
|
|
});
|
|
|
|
update();
|
|
|
|
$(window).on('hashchange', function() {
|
|
parseUrlToState();
|
|
update()
|
|
});
|
|
|
|
$('[data-toggle="tooltip"]').tooltip();
|
|
});
|
|
</script>
|
|
|
|
<style type="text/css">
|
|
</style>
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<div class="container" id="container">
|
|
<div class="row text-center">
|
|
<h1>Shaker | The Report</h1>
|
|
</div>
|
|
<hr>
|
|
<div class="row">
|
|
<div class="col-md-2">
|
|
<label for="scenario_selector" title="Scenario name">Scenario</label>
|
|
<select id="scenario_selector" class="form-control" data-placeholder="- Any scenario -"></select>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<label for="test_selector" title="Test name">Test Case</label>
|
|
<select id="test_selector" class="form-control" data-placeholder="- Any test case -"></select>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<label for="concurrency_selector" title="Concurrency">Concurrency</label>
|
|
<select id="concurrency_selector" class="form-control" data-placeholder="- Any concurrency -"></select>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<label for="node_selector" title="Host / Compute node">Host</label>
|
|
<select id="node_selector" class="form-control" data-placeholder="- Any node -"></select>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<label for="agent_selector" title="Agent">Agent</label>
|
|
<select id="agent_selector" class="form-control" data-placeholder="- Any agent -"></select>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="content_area" class="row">
|
|
<!-- Container for the screen content -->
|
|
</div>
|
|
|
|
<div id="footer" class="row"> </div>
|
|
</div>
|
|
|
|
<!-- TEMPLATES --------------------------------------------------------------->
|
|
|
|
<!-- Scenario File -->
|
|
<script id="scenario_source_template" type="text/x-handlebars-template">
|
|
<h3>Scenario</h3>
|
|
<pre>{{ data }}</pre>
|
|
</script>
|
|
|
|
<!-- Test Specification -->
|
|
<script id="test_specification_template" type="text/x-handlebars-template">
|
|
<h3>Test Specification</h3>
|
|
<pre>{{ data }}</pre>
|
|
</script>
|
|
|
|
<!-- Executor Result -->
|
|
<script id="executor_template" type="text/x-handlebars-template">
|
|
<h3>Execution Summary</h3>
|
|
{{#with record}}
|
|
<div id="{{ chart_id }}"></div>
|
|
{{#if is_status_ok}}<span class="label label-success"><span class="glyphicon glyphicon-ok" aria-hidden="true"></span>success</span>{{/if}}
|
|
{{#if is_status_lost}}<span class="label label-danger"><span class="glyphicon glyphicon-alert" aria-hidden="true"></span>lost</span>{{/if}}
|
|
{{#if is_status_interrupted}}<span class="label label-warning"><span class="glyphicon glyphicon-stop" aria-hidden="true"></span>interrupted</span>{{/if}}
|
|
{{#if is_status_error}}<span class="label label-danger"><span class="glyphicon glyphicon-alert" aria-hidden="true"></span>error</span>{{/if}}
|
|
{{#if is_status_fail}}<span class="label label-danger"><span class="glyphicon glyphicon-alert" aria-hidden="true"></span>sla fail</span>{{/if}}
|
|
{{#if stats_yaml}}
|
|
<h4>Stats</h4>
|
|
<pre>{{ stats_yaml }}</pre>
|
|
{{/if}}
|
|
{{#if time_info}}
|
|
<h4>Time Info</h4>
|
|
<pre>{{ time_info }}</pre>
|
|
{{/if}}
|
|
<h4>Command</h4>
|
|
<pre>{{ command_yaml }}</pre>
|
|
{{#if stdout}}
|
|
<h4>Stdout</h4>
|
|
<pre>{{ stdout }}</pre>
|
|
{{/if}}
|
|
{{#if verbose}}
|
|
<h4>Verbose Info</h4>
|
|
<pre>{{ verbose }}</pre>
|
|
{{/if}}
|
|
{{#if stderr}}
|
|
<h4>Stderr</h4>
|
|
<pre>{{ stderr }}</pre>
|
|
{{/if}}
|
|
{{/with}}
|
|
</script>
|
|
|
|
<!-- Concurrency summary -->
|
|
<script id="concurrency_summary_template" type="text/x-handlebars-template">
|
|
{{#with record}}
|
|
<div id="{{ chart_id }}"></div>
|
|
<h3>Per-node chart</h3>
|
|
<div id="{{ node_chart_id }}"></div>
|
|
<h3>Stats</h3>
|
|
<pre>{{ stats_yaml }}</pre>
|
|
{{/with}}
|
|
</script>
|
|
|
|
<!-- Test summary -->
|
|
<script id="test_summary_template" type="text/x-handlebars-template">
|
|
{{#with record}}
|
|
<div id="{{ chart_id }}"></div>
|
|
{{#if stats_yaml}}
|
|
<h3>Stats</h3>
|
|
<pre>{{ stats_yaml }}</pre>
|
|
{{/if}}
|
|
{{/with}}
|
|
</script>
|
|
|
|
<!-- Records Table -->
|
|
<script id="records_table_template" type="text/x-handlebars-template">
|
|
<h3>Records</h3>
|
|
<table class="table table-striped" id="{{ table_id }}">
|
|
<thead>
|
|
<tr>
|
|
<th>Scenario</th>
|
|
<th>Test Case</th>
|
|
<th>Concurrency</th>
|
|
<th>Host / Compute Node</th>
|
|
<th>Agent</th>
|
|
<th>Status</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{{#records}}
|
|
<tr>
|
|
<td><a href="{{ scenario_url }}">{{ scenario }}</a></td>
|
|
<td><a href="{{ test_url }}">{{ test }}</a></td>
|
|
<td><a href="{{ concurrency_url }}">{{ concurrency }}</a></td>
|
|
<td><a href="{{ node_url }}">{{ node }}</a></td>
|
|
<td><a href="{{ agent_url }}">{{ agent }}</a></td>
|
|
<td>
|
|
{{#if is_status_ok }}
|
|
<span class="label label-success">
|
|
<span class="glyphicon glyphicon-ok" aria-hidden="true"></span>
|
|
success
|
|
</span>
|
|
{{/if}}
|
|
{{#if is_status_lost }}
|
|
<span class="label label-danger">
|
|
<span class="glyphicon glyphicon-alert" aria-hidden="true"></span>
|
|
lost
|
|
</span>
|
|
{{/if}}
|
|
{{#if is_status_interrupted }}
|
|
<span class="label label-warning">
|
|
<span class="glyphicon glyphicon-stop" aria-hidden="true"></span>
|
|
interrupted
|
|
</span>
|
|
{{/if}}
|
|
{{#if is_status_error }}
|
|
<span class="label label-danger">
|
|
<span class="glyphicon glyphicon-stop" aria-hidden="true"></span>
|
|
error
|
|
</span>
|
|
{{/if}}
|
|
{{#if is_status_fail }}
|
|
<span class="label label-danger">
|
|
<span class="glyphicon glyphicon-alert" aria-hidden="true"></span>
|
|
sla fail
|
|
</span>
|
|
{{/if}}
|
|
</td>
|
|
</tr>
|
|
{{/records}}
|
|
</tbody>
|
|
</table>
|
|
</script>
|
|
|
|
<!-- Agents List -->
|
|
<script id="agents_table_template" type="text/x-handlebars-template">
|
|
<h3>Agents</h3>
|
|
<table class="table table-striped" id="{{ table_id }}">
|
|
<thead>
|
|
<tr>
|
|
<th>Agent</th>
|
|
<th>Mode</th>
|
|
<th>IP</th>
|
|
<th>Node</th>
|
|
<th>AZ</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{{#agents}}
|
|
<tr>
|
|
<td>{{ id }}</td>
|
|
<td>{{ mode }}</td>
|
|
<td>{{ ip }}</td>
|
|
<td>{{ node }}</td>
|
|
<td>{{ zone }}</td>
|
|
</tr>
|
|
{{/agents}}
|
|
</tbody>
|
|
</table>
|
|
</script>
|
|
|
|
<!-- SLA List -->
|
|
<script id="sla_table_template" type="text/x-handlebars-template">
|
|
<h3>Agents</h3>
|
|
<table class="table table-striped" id="{{ table_id }}">
|
|
<thead>
|
|
<tr>
|
|
<th>Condition</th>
|
|
<th>Location</th>
|
|
<th>Status</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{{#records}}
|
|
<tr>
|
|
<td>{{ sla }}</td>
|
|
<td>{{ location }}</td>
|
|
<td>
|
|
{{#if is_status_ok }}
|
|
<span class="text-success">
|
|
<span class="glyphicon glyphicon-ok" aria-hidden="true"></span>
|
|
{{ status }}
|
|
</span>
|
|
{{else}}
|
|
<span class="text-danger">
|
|
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
|
|
{{ status }}
|
|
</span>
|
|
{{/if}}
|
|
</td>
|
|
</tr>
|
|
{{/records}}
|
|
</tbody>
|
|
</table>
|
|
</script>
|
|
|
|
<!-- Errors -->
|
|
<script id="errors_template" type="text/x-handlebars-template">
|
|
<h3>Errors</h3>
|
|
<div class="text-danger">
|
|
<ul>
|
|
{{#records}}
|
|
<li>{{ info }}<br/>{{ stderr }}{{ traceback }}</li>
|
|
{{/records}}
|
|
</ul>
|
|
</div>
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|