Alex | b78191f | 2021-11-02 16:35:46 -0500 | [diff] [blame^] | 1 | <!DOCTYPE html> |
| 2 | <html lang="en"> |
| 3 | <head> |
| 4 | <meta charset="UTF-8"> |
| 5 | <title>cfg-checker agent</title> |
| 6 | {% include 'common_styles.j2' %} |
| 7 | {% include 'common_scripts.j2' %} |
| 8 | <script language="JavaScript"> |
| 9 | const getJSON = async url => { |
| 10 | const response = await fetch(url); |
| 11 | if(!response.ok) // check if response worked (no 404 errors etc...) |
| 12 | throw new Error(response.statusText); |
| 13 | |
| 14 | const data = response.json(); // get JSON from the response |
| 15 | return data; // returns a promise, which resolves to this data value |
| 16 | } |
| 17 | |
| 18 | function qStatus(uri, tagId) { |
| 19 | var dt, el; |
| 20 | |
| 21 | el = document.getElementById(tagId); |
| 22 | el.innerHTML = "calling " + uri; |
| 23 | |
| 24 | getJSON(uri).then(data => { |
| 25 | el.innerHTML = "<pre>" + JSON.stringify(data, null, ' ') + "</pre>"; |
| 26 | }).catch(error => { |
| 27 | el.innerHTML = JSON.stringify(error, null, ' '); |
| 28 | }); |
| 29 | }; |
| 30 | |
| 31 | function updateModules() { |
| 32 | var _n, _v, _hc, _s, _phead, _p; |
| 33 | |
| 34 | let mods = []; |
| 35 | // Jinja populated list |
| 36 | {% for mod in modules %} |
| 37 | mods.push("{{ mod }}"); |
| 38 | {% endfor %} |
| 39 | |
| 40 | mods.forEach((mod) => { |
| 41 | // get all ids needed to fill |
| 42 | _n = document.getElementById(mod + "_name"); |
| 43 | _v = document.getElementById(mod + "_version"); |
| 44 | _hc = document.getElementById(mod + "_healthcheck"); |
| 45 | _s = document.getElementById(mod + "_status"); |
| 46 | _phead = document.getElementById(mod + "_progress_head"); |
| 47 | _p = document.getElementById(mod + "_progress"); |
| 48 | |
| 49 | // Fill |
| 50 | _n.innerHTML = mod; |
| 51 | // get status |
| 52 | getJSON("api/" + mod).then(data => { |
| 53 | _v.innerHTML = data['healthcheck']['version']; |
| 54 | _hc.innerHTML = data['healthcheck']['ready']; |
| 55 | _s.innerHTML = data['status']; |
| 56 | if ((data['status'] == "idle") || (data['status'] == "finished")) { |
| 57 | if (_phead.className.indexOf("idle") < 0) { |
| 58 | _phead.className += " idle"; |
| 59 | } |
| 60 | } |
| 61 | else if (data['status'] == "running") { |
| 62 | _phead.className = _phead.className.replace(" idle", ""); |
| 63 | } |
| 64 | _p.style.width = data['progress'] + "%"; |
| 65 | }).catch(error => { |
| 66 | _v.innerHTML = "?"; |
| 67 | _hc.innerHTML = "No response"; |
| 68 | _s.innerHTML = "Unknown"; |
| 69 | _phead.className = _phead.className.replace(" idle", ""); |
| 70 | // set bar status to red later |
| 71 | //_p.style.width = "100%"; |
| 72 | }); |
| 73 | }) |
| 74 | }; |
| 75 | var interval = 500; |
| 76 | setInterval(updateModules, interval); |
| 77 | </script> |
| 78 | <style> |
| 79 | .barcontent { |
| 80 | margin: auto; |
| 81 | width: 1350px; |
| 82 | padding: 10px; |
| 83 | } |
| 84 | .bar-centered { |
| 85 | float: none; |
| 86 | transform: translate(25%); |
| 87 | } |
| 88 | .agent_labels { |
| 89 | display: inline-block; |
| 90 | margin: 0px; |
| 91 | margin-right: 5px; |
| 92 | |
| 93 | } |
| 94 | .info_label { |
| 95 | font-family: "LaoSangamMN", Monaco, monospace; |
| 96 | display: block; |
| 97 | float: left; |
| 98 | box-sizing: content-box; |
| 99 | background: #262; |
| 100 | color: white; |
| 101 | border-radius: 5px; |
| 102 | text-align: center; |
| 103 | padding: 0px 5px 5px 5px; |
| 104 | height: 14px; |
| 105 | margin: 5px 2px 5px 2px; |
| 106 | } |
| 107 | .gray_bg { background: #444; } |
| 108 | .section_head { font-size: 0.8em; color: Navy; padding-left: 2px; } |
| 109 | .row_button { |
| 110 | background-color: #468; |
| 111 | color: #fff; |
| 112 | cursor: pointer; |
| 113 | padding: 5px; |
| 114 | width: 100%; |
| 115 | border: none; |
| 116 | text-align: left; |
| 117 | outline: none; |
| 118 | font-size: 13px; |
| 119 | } |
| 120 | .row_button:after { |
| 121 | content: '\02795'; /* Unicode character for "plus" sign (+) */ |
| 122 | font-size: 13px; |
| 123 | color: white; |
| 124 | float: left; |
| 125 | margin-left: 5px; |
| 126 | } |
| 127 | |
| 128 | .row_active:after { |
| 129 | content: "\2796"; /* Unicode character for "minus" sign (-) */ |
| 130 | color: white |
| 131 | } |
| 132 | |
| 133 | .row_active, .row_button:hover { |
| 134 | background-color: #68a; |
| 135 | color: white |
| 136 | } |
| 137 | |
| 138 | .cell_button { |
| 139 | color: darkgreen; |
| 140 | cursor: pointer; |
| 141 | padding: 5px; |
| 142 | width: 100%; |
| 143 | border: none; |
| 144 | text-align: center; |
| 145 | outline: none; |
| 146 | } |
| 147 | .cell_button:hover { |
| 148 | background-color: gray; |
| 149 | } |
| 150 | |
| 151 | .tooltiptext { |
| 152 | transform: translate(100px); |
| 153 | } |
| 154 | |
| 155 | .console { |
| 156 | background-color: black; |
| 157 | font-family: "Lucida Console", Monaco, monospace; |
| 158 | font-size: 0.5em; |
| 159 | width: auto; |
| 160 | color: #fff; |
| 161 | border-radius: 6px; |
| 162 | padding: 5px 5px; |
| 163 | } |
| 164 | |
| 165 | .progress { |
| 166 | box-sizing: content-box; |
| 167 | height: 10px; /* Can be anything */ |
| 168 | position: relative; |
| 169 | background: #aaa; |
| 170 | border-radius: 5px; |
| 171 | padding: 5px; |
| 172 | box-shadow: inset 0 -1px 1px rgba(255, 255, 255, 0.3); |
| 173 | } |
| 174 | .progress > span { |
| 175 | display: block; |
| 176 | height: 100%; |
| 177 | border-top-right-radius: 3px; |
| 178 | border-bottom-right-radius: 3px; |
| 179 | border-top-left-radius: 5px; |
| 180 | border-bottom-left-radius: 5px; |
| 181 | background-color: rgb(43, 194, 83); |
| 182 | background-image: linear-gradient( |
| 183 | center bottom, |
| 184 | rgb(43, 194, 83) 37%, |
| 185 | rgb(84, 240, 84) 69% |
| 186 | ); |
| 187 | position: relative; |
| 188 | overflow: hidden; |
| 189 | } |
| 190 | .progress > span:after, |
| 191 | .animate > span > span { |
| 192 | content: ""; |
| 193 | position: absolute; |
| 194 | top: 0; |
| 195 | left: 0; |
| 196 | bottom: 0; |
| 197 | right: 0; |
| 198 | background-image: linear-gradient( |
| 199 | -45deg, |
| 200 | rgba(255, 255, 255, 0.1) 25%, |
| 201 | transparent 25%, |
| 202 | transparent 50%, |
| 203 | rgba(255, 255, 255, 0.1) 50%, |
| 204 | rgba(255, 255, 255, 0.1) 75%, |
| 205 | transparent 75%, |
| 206 | transparent |
| 207 | ); |
| 208 | z-index: 1; |
| 209 | background-size: 50px 50px; |
| 210 | animation: move 2s linear infinite; |
| 211 | border-top-right-radius: 8px; |
| 212 | border-bottom-right-radius: 8px; |
| 213 | border-top-left-radius: 20px; |
| 214 | border-bottom-left-radius: 20px; |
| 215 | overflow: hidden; |
| 216 | } |
| 217 | |
| 218 | .animate > span:after { |
| 219 | display: none; |
| 220 | } |
| 221 | |
| 222 | @keyframes move { |
| 223 | 0% { |
| 224 | background-position: 0 0; |
| 225 | } |
| 226 | 100% { |
| 227 | background-position: 50px 50px; |
| 228 | } |
| 229 | } |
| 230 | |
| 231 | .bluewish > span { |
| 232 | background-image: linear-gradient(#3d52b1, #3052b1); |
| 233 | } |
| 234 | .idle > span > span, |
| 235 | .idle > span::after { |
| 236 | background-image: none; |
| 237 | } |
| 238 | </style> |
| 239 | </head> |
| 240 | <body onload="init()"> |
| 241 | |
| 242 | <div class="header"> |
| 243 | <div class="label date">generated on: {{ gen_date }}</div> |
| 244 | </div> |
| 245 | |
| 246 | <div class="bar"> |
| 247 | <div class="bar-centered"> |
| 248 | <button class="bar-item" onclick="openBar(event, 'status')">Status</button> |
| 249 | </div> |
| 250 | </div> |
| 251 | |
| 252 | {% macro status_page(info, id_label) %} |
| 253 | <div id="{{ id_label }}" class="barcontent"> |
| 254 | <h5>{{ caller() }}</h5> |
| 255 | <hr> |
| 256 | <div class="agent_labels"> |
| 257 | <div class="info_label" onclick="updateModules()">{{ hostname }}</div> |
| 258 | <div class="info_label">{{ system }}</div> |
| 259 | <div class="info_label">{{ release }}</div> |
| 260 | <div class="info_label gray_bg">Started: {{ agent['started'] }}</div> |
| 261 | </div> |
| 262 | <hr> |
| 263 | {% for mod in modules %} |
| 264 | <div class="agent_labels"> |
| 265 | <div class="info_label" id="{{ mod }}_name">{{ mod }}</div> |
| 266 | <div class="info_label" id="{{ mod }}_version">unknown</div> |
| 267 | <div class="info_label" id="{{ mod }}_healthcheck">unknown</div> |
| 268 | <div class="info_label" id="{{ mod }}_status">unknown</div> |
| 269 | </div> |
| 270 | <div class="progress bluewish idle" id="{{ mod }}_progress_head"> |
| 271 | <span style="width: 0%" id="{{ mod }}_progress"></span> |
| 272 | </div> |
| 273 | <hr> |
| 274 | {% endfor %} |
| 275 | <div class="section_head">REST Api help:</div> |
| 276 | {% for uri, ops in help.items() %} |
| 277 | <div class="console"> |
| 278 | <div class="">{{ uri | escape }}</div> |
| 279 | {% for op, op_help in ops.items() %} |
| 280 | <div class="">{{ op }}: {{ op_help | escape }}</div> |
| 281 | {% endfor %} |
| 282 | </div> |
| 283 | <br> |
| 284 | {% endfor %} |
| 285 | <div class="section_head">Available modules: {{ modules | join(", ")}}</div> |
| 286 | <div class="section_head">Agent:</div> |
| 287 | <div class="console" onclick="qStatus('api/','agent')"> |
| 288 | <div class="" id="agent"></div> |
| 289 | </div> |
| 290 | |
| 291 | <div class="section_head">Status json:</div> |
| 292 | <div class="console" onclick="qStatus('api/{{ modules[0] }}','fio')"> |
| 293 | <div class="" id="fio"></div> |
| 294 | </div> |
| 295 | |
| 296 | |
| 297 | </div> |
| 298 | {% endmacro %} |
| 299 | |
| 300 | |
| 301 | {% call status_page(info, "status") %} |
| 302 | Agent status |
| 303 | {% endcall %} |
| 304 | </body> |
| 305 | </html> |