blob: ff8f613e2c1666d9aec1ada6ff8073750480940d [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>cfg-checker agent</title>
{% include 'common_styles.j2' %}
{% include 'common_scripts.j2' %}
<script language="JavaScript">
const getJSON = async url => {
const response = await fetch(url);
if(!response.ok) // check if response worked (no 404 errors etc...)
throw new Error(response.statusText);
const data = response.json(); // get JSON from the response
return data; // returns a promise, which resolves to this data value
}
function qStatus(uri, tagId) {
var dt, el;
el = document.getElementById(tagId);
el.innerHTML = "calling " + uri;
getJSON(uri).then(data => {
el.innerHTML = "<pre>" + JSON.stringify(data, null, ' ') + "</pre>";
}).catch(error => {
el.innerHTML = JSON.stringify(error, null, ' ');
});
};
function updateModules() {
var _n, _v, _hc, _s, _phead, _p;
let mods = [];
// Jinja populated list
{% for mod in modules %}
mods.push("{{ mod }}");
{% endfor %}
mods.forEach((mod) => {
// get all ids needed to fill
_n = document.getElementById(mod + "_name");
_v = document.getElementById(mod + "_version");
_hc = document.getElementById(mod + "_healthcheck");
_s = document.getElementById(mod + "_status");
_phead = document.getElementById(mod + "_progress_head");
_p = document.getElementById(mod + "_progress");
// Fill
_n.innerHTML = mod;
// get status
getJSON("api/" + mod).then(data => {
_v.innerHTML = data['healthcheck']['version'];
_hc.innerHTML = data['healthcheck']['ready'];
_s.innerHTML = data['status'];
if ((data['status'] == "idle") || (data['status'] == "finished")) {
if (_phead.className.indexOf("idle") < 0) {
_phead.className += " idle";
}
}
else if (data['status'] == "running") {
_phead.className = _phead.className.replace(" idle", "");
}
_p.style.width = data['progress'] + "%";
}).catch(error => {
_v.innerHTML = "?";
_hc.innerHTML = "No response";
_s.innerHTML = "Unknown";
_phead.className = _phead.className.replace(" idle", "");
// set bar status to red later
//_p.style.width = "100%";
});
})
};
var interval = 500;
setInterval(updateModules, interval);
</script>
<style>
.barcontent {
margin: auto;
width: 1350px;
padding: 10px;
}
.bar-centered {
float: none;
transform: translate(25%);
}
.agent_labels {
display: inline-block;
margin: 0px;
margin-right: 5px;
}
.info_label {
font-family: "LaoSangamMN", Monaco, monospace;
display: block;
float: left;
box-sizing: content-box;
background: #262;
color: white;
border-radius: 5px;
text-align: center;
padding: 0px 5px 5px 5px;
height: 14px;
margin: 5px 2px 5px 2px;
}
.gray_bg { background: #444; }
.section_head { font-size: 0.8em; color: Navy; padding-left: 2px; }
.row_button {
background-color: #468;
color: #fff;
cursor: pointer;
padding: 5px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 13px;
}
.row_button:after {
content: '\02795'; /* Unicode character for "plus" sign (+) */
font-size: 13px;
color: white;
float: left;
margin-left: 5px;
}
.row_active:after {
content: "\2796"; /* Unicode character for "minus" sign (-) */
color: white
}
.row_active, .row_button:hover {
background-color: #68a;
color: white
}
.cell_button {
color: darkgreen;
cursor: pointer;
padding: 5px;
width: 100%;
border: none;
text-align: center;
outline: none;
}
.cell_button:hover {
background-color: gray;
}
.tooltiptext {
transform: translate(100px);
}
.console {
background-color: black;
font-family: "Lucida Console", Monaco, monospace;
font-size: 0.5em;
width: auto;
color: #fff;
border-radius: 6px;
padding: 5px 5px;
}
.progress {
box-sizing: content-box;
height: 10px; /* Can be anything */
position: relative;
background: #aaa;
border-radius: 5px;
padding: 5px;
box-shadow: inset 0 -1px 1px rgba(255, 255, 255, 0.3);
}
.progress > span {
display: block;
height: 100%;
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
background-color: rgb(43, 194, 83);
background-image: linear-gradient(
center bottom,
rgb(43, 194, 83) 37%,
rgb(84, 240, 84) 69%
);
position: relative;
overflow: hidden;
}
.progress > span:after,
.animate > span > span {
content: "";
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
background-image: linear-gradient(
-45deg,
rgba(255, 255, 255, 0.1) 25%,
transparent 25%,
transparent 50%,
rgba(255, 255, 255, 0.1) 50%,
rgba(255, 255, 255, 0.1) 75%,
transparent 75%,
transparent
);
z-index: 1;
background-size: 50px 50px;
animation: move 2s linear infinite;
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
border-top-left-radius: 20px;
border-bottom-left-radius: 20px;
overflow: hidden;
}
.animate > span:after {
display: none;
}
@keyframes move {
0% {
background-position: 0 0;
}
100% {
background-position: 50px 50px;
}
}
.bluewish > span {
background-image: linear-gradient(#3d52b1, #3052b1);
}
.idle > span > span,
.idle > span::after {
background-image: none;
}
</style>
</head>
<body onload="init()">
<div class="header">
<div class="label date">generated on: {{ gen_date }}</div>
</div>
<div class="bar">
<div class="bar-centered">
<button class="bar-item" onclick="openBar(event, 'status')">Status</button>
</div>
</div>
{% macro status_page(info, id_label) %}
<div id="{{ id_label }}" class="barcontent">
<h5>{{ caller() }}</h5>
<hr>
<div class="agent_labels">
<div class="info_label" onclick="updateModules()">{{ hostname }}</div>
<div class="info_label">{{ system }}</div>
<div class="info_label">{{ release }}</div>
<div class="info_label gray_bg">Started: {{ agent['started'] }}</div>
</div>
<hr>
{% for mod in modules %}
<div class="agent_labels">
<div class="info_label" id="{{ mod }}_name">{{ mod }}</div>
<div class="info_label" id="{{ mod }}_version">unknown</div>
<div class="info_label" id="{{ mod }}_healthcheck">unknown</div>
<div class="info_label" id="{{ mod }}_status">unknown</div>
</div>
<div class="progress bluewish idle" id="{{ mod }}_progress_head">
<span style="width: 0%" id="{{ mod }}_progress"></span>
</div>
<hr>
{% endfor %}
<div class="section_head">REST Api help:</div>
{% for uri, ops in help.items() %}
<div class="console">
<div class="">{{ uri | escape }}</div>
{% for op, op_help in ops.items() %}
<div class="">{{ op }}: {{ op_help | escape }}</div>
{% endfor %}
</div>
<br>
{% endfor %}
<div class="section_head">Available modules: {{ modules | join(", ")}}</div>
<div class="section_head">Agent:</div>
<div class="console" onclick="qStatus('api/','agent')">
<div class="" id="agent"></div>
</div>
<div class="section_head">Status json:</div>
<div class="console" onclick="qStatus('api/{{ modules[0] }}','fio')">
<div class="" id="fio"></div>
</div>
</div>
{% endmacro %}
{% call status_page(info, "status") %}
Agent status
{% endcall %}
</body>
</html>