summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--modules-available/dnbd3/inc/dnbd3rpc.inc.php44
-rw-r--r--modules-available/dnbd3/page.inc.php79
-rw-r--r--modules-available/dnbd3/templates/page-proxy-images.html86
-rw-r--r--modules-available/dnbd3/templates/page-proxy-stats.html10
4 files changed, 199 insertions, 20 deletions
diff --git a/modules-available/dnbd3/inc/dnbd3rpc.inc.php b/modules-available/dnbd3/inc/dnbd3rpc.inc.php
index 6ed43254..6e7480c0 100644
--- a/modules-available/dnbd3/inc/dnbd3rpc.inc.php
+++ b/modules-available/dnbd3/inc/dnbd3rpc.inc.php
@@ -6,20 +6,7 @@ class Dnbd3Rpc {
const QUERY_NOT_200 = 2;
const QUERY_NOT_JSON = 3;
- /**
- * Query given DNBD3 server for status information.
- *
- * @param string $server server address
- * @param int $port server port
- * @param bool $stats include general stats
- * @param bool $clients include client list
- * @param bool $images include image list
- * @param bool $diskSpace include disk space stats
- * @param bool $config get config
- * @param bool $altservers list of alt servers with status
- * @return int|array the queried data as an array, or false on error
- */
- public static function query($server, $stats, $clients, $images, $diskSpace = false, $config = false, $altservers = false)
+ private static function translateServer($server)
{
// Special case - local server
if ($server === '<self>') {
@@ -36,6 +23,24 @@ class Dnbd3Rpc {
$server .= ':5003';
}
}
+ return $server;
+ }
+
+ /**
+ * Query given DNBD3 server for status information.
+ *
+ * @param string $server server address
+ * @param bool $stats include general stats
+ * @param bool $clients include client list
+ * @param bool $images include image list
+ * @param bool $diskSpace include disk space stats
+ * @param bool $config get config
+ * @param bool $altservers list of alt servers with status
+ * @return int|array the queried data as an array, or false on error
+ */
+ public static function query($server, $stats, $clients, $images, $diskSpace = false, $config = false, $altservers = false)
+ {
+ $server = self::translateServer($server);
$url = 'http://' . $server . '/query?';
if ($stats) {
$url .= 'q=stats&';
@@ -66,4 +71,15 @@ class Dnbd3Rpc {
return $ret;
}
+ public static function getCacheMap($server, $imgId)
+ {
+ $server = self::translateServer($server);
+ $str = Download::asString('http://' . $server . '/cachemap?id=' . $imgId, 3, $code);
+ if ($str === false)
+ return self::QUERY_UNREACHABLE;
+ if ($code !== 200)
+ return self::QUERY_NOT_200;
+ return $str;
+ }
+
}
diff --git a/modules-available/dnbd3/page.inc.php b/modules-available/dnbd3/page.inc.php
index 4a32b0a3..87169a03 100644
--- a/modules-available/dnbd3/page.inc.php
+++ b/modules-available/dnbd3/page.inc.php
@@ -264,6 +264,9 @@ class Page_Dnbd3 extends Page
foreach (['bytesSent', 'bytesReceived', 'spaceTotal', 'spaceFree'] as $key) {
$stats[$key . '_s'] = Util::readableFileSize($stats[$key]);
}
+ if ($stats['bytesReceived'] > 0) {
+ $stats['ratio'] = round($stats['bytesSent'] / $stats['bytesReceived'], 2);
+ }
if ($stats['spaceTotal'] > 0) {
$stats['percentFree'] = ($stats['spaceFree'] / $stats['spaceTotal']) * 100;
$stats['percentFree'] = round($stats['percentFree'], $stats['percentFree'] < 10 ? 1 : 0);
@@ -294,7 +297,20 @@ class Page_Dnbd3 extends Page
} else {
$extra = '';
$class2 = 'slx-bold';
- if (in_array($line['key'], ['serverPenalty', 'clientPenalty'])) {
+ if ($line['key'] === 'autoFreeDiskSpaceDelay') {
+ $v = (int)$line['val'];
+ if ($v >= 3600 * 24) {
+ $extra = floor($v / (3600 * 24)) . 'd ';
+ $v %= 3600 * 24;
+ }
+ if ($v >= 3600) {
+ $extra .= floor($v / 3600) . 'h ';
+ $v %= 3600;
+ }
+ if ($v >= 60) {
+ $extra .= floor($v / 60) . 'm ';
+ }
+ } elseif (in_array($line['key'], ['serverPenalty', 'clientPenalty'])) {
$extra = round($line['val'] / 1000, 1) . 'ms';
} elseif (in_array($line['key'], ['uplinkTimeout', 'clientTimeout'])) {
$extra = round($line['val'] / 1000, 1) . 's';
@@ -367,6 +383,15 @@ class Page_Dnbd3 extends Page
$sort2[] = $image['name'];
}
array_multisort($sort1, SORT_NUMERIC | SORT_DESC, $sort2, SORT_ASC, $stats['images']);
+ $stats['serverId'] = $server['serverId'];
+ // Colors for bars
+ $stats['colors'] = [];
+ for ($i = 0; $i < 16; ++$i) {
+ $dark = dechex(max(0, $i - 3));
+ $normal = dechex($i);
+ $extra = dechex(max(0, $i - 12));
+ $stats['colors'][] = ['i' => $i, 'dark' => "#0{$dark}0", 'bright' => "#$extra$normal$extra"];
+ }
Render::addTemplate('page-proxy-images', $stats);
Render::closeTag('div');
}
@@ -416,7 +441,7 @@ class Page_Dnbd3 extends Page
WHERE s.serverid = :serverId', compact('serverId'));
if ($server === false) {
if (AJAX)
- die('Invalid server id');
+ die('Invalid server id: ' . $serverId);
Message::addError('server-non-existent', $serverId);
Util::redirect('?do=dnbd3');
}
@@ -427,6 +452,7 @@ class Page_Dnbd3 extends Page
} else {
$server['ip'] = '127.0.0.1';
}
+ $server['serverId'] = $serverId;
return $server;
}
@@ -455,6 +481,8 @@ class Page_Dnbd3 extends Page
$this->ajaxEditServer();
} elseif ($action === 'reboot') {
$this->ajaxReboot();
+ } elseif ($action === 'cachemap') {
+ $this->ajaxCacheMap();
} else {
die($action . '???');
}
@@ -545,4 +573,51 @@ class Page_Dnbd3 extends Page
die(json_encode($status));
}
+ private function ajaxCacheMap()
+ {
+ $server = $this->getServerById();
+ $imgId = Request::any('id', 0, 'int');
+ if ($imgId <= 0) {
+ Header('HTTP/1.1 400 Bad Request');
+ die('Invalid/no image id');
+ }
+ $data = Dnbd3Rpc::getCacheMap($server['ip'], $imgId);
+ if ($data === Dnbd3Rpc::QUERY_UNREACHABLE) {
+ Header('HTTP/1.1 504 Gateway Timeout');
+ die('Proxy not reachable');
+ }
+ if ($data === Dnbd3Rpc::QUERY_NOT_200) {
+ Header('HTTP/1.1 503 Service Unavailable');
+ die("Proxy didn't reply with 200 OK");
+ }
+ Header('Content-Type: application/octet-stream');
+ die($data);
+ }
+
+ private function genChunk($acc)
+ {
+ static $last = -1;
+ static $count = 0;
+ if ($acc !== false) {
+ if ($acc > 15) {
+ $acc = 15;
+ }
+ $acc = round($acc);
+ if ($last === $acc) {
+ $count++;
+ return '';
+ }
+ }
+ if ($last !== -1) {
+ if ($count === 1)
+ return '<b style="background:#0' . dechex($acc) . '0"></b>';
+ $line = '<b style="background:#0' . dechex($last) . '0;flex-grow:' . $count . '"></b>';
+ } else {
+ $line = '';
+ }
+ $last = $acc;
+ $count = 1;
+ return $line;
+ }
+
}
diff --git a/modules-available/dnbd3/templates/page-proxy-images.html b/modules-available/dnbd3/templates/page-proxy-images.html
index ff420ffd..3ec4908c 100644
--- a/modules-available/dnbd3/templates/page-proxy-images.html
+++ b/modules-available/dnbd3/templates/page-proxy-images.html
@@ -21,7 +21,7 @@
{{size_s}}
</td>
<td class="text-right text-nowrap">
- {{complete}}&thinsp;%
+ <a data-imgid="{{id}}" class="cache-map" href="#">{{complete}}&thinsp;%</a>
</td>
<td class="text-right text-nowrap">
{{idle_s}}
@@ -33,3 +33,87 @@
{{/images}}
</table>
</div>
+
+<style type="text/css">
+ .cmbar {
+ display: flex;
+ width: 250px;
+ align-items: stretch;
+ padding: 0;
+ }
+ .cmbar b {
+ display: inline-block;
+ flex-grow: 1;
+ height: 1em;
+ margin: 0;
+ }
+ {{#colors}}
+ .cmbar .a{{i}} {background: linear-gradient({{dark}}, {{bright}}, {{dark}})}
+ {{/colors}}
+</style>
+
+<script>
+ document.addEventListener('DOMContentLoaded', function () {
+ $('.cache-map').click(function (e) {
+ e.preventDefault();
+ var $this = $(this);
+ // Use xhr directly as jQuery doesn't support arraybuffer
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', '?do=dnbd3&action=cachemap&server={{serverId}}&id=' + $this.data('imgid') + '&raw=1&async=1', true);
+ xhr.responseType = 'arraybuffer';
+ xhr.onload = function(e) {
+ if (this.readyState !== 4)
+ return;
+ var ua = new Uint8Array(this.response);
+ console.log(ua);
+ if (this.status !== 200) {
+ $this.replaceWith($('<span>').text(typeof TextDecoder !== 'undefined' ? new TextDecoder("utf-8").decode(ua) : 'HTTP ' + this.status));
+ return;
+ }
+ var llast = -1;
+ var lcount = 0;
+ var genChunk = function(acc) {
+ var line;
+ if (acc !== false) {
+ if (acc > 15) acc = 15; else acc = (acc + 0.49) | 0;
+ if (llast === acc) {
+ lcount++;
+ return '';
+ }
+ }
+ if (llast !== -1 || acc === false) {
+ if (lcount === 1) {
+ line = '<b class="a' + llast + '"></b>';
+ } else {
+ line = '<b class="a' + llast + '" style="flex-grow:' + lcount + '"></b>';
+ }
+ } else {
+ line = '';
+ }
+ llast = acc;
+ lcount = 1;
+ return line;
+ };
+ var l = ua.length;
+ var div;
+ if (l >= 240) {
+ div = l / 120;
+ } else {
+ div = 1;
+ }
+ var acc = 0, target = div, div16 = div * 16, html = '';
+ for (var i = 0; i < l; ++i) {
+ acc += ua[i];
+ if (i + 1 >= target) {
+ html += genChunk(acc / (div16));
+ acc = 0;
+ target += div;
+ }
+ }
+ html += genChunk(false);
+ $this.replaceWith($('<div class="cmbar">').html(html));
+ };
+ xhr.send();
+ });
+ });
+</script>
diff --git a/modules-available/dnbd3/templates/page-proxy-stats.html b/modules-available/dnbd3/templates/page-proxy-stats.html
index a866903c..9c3a4a84 100644
--- a/modules-available/dnbd3/templates/page-proxy-stats.html
+++ b/modules-available/dnbd3/templates/page-proxy-stats.html
@@ -1,11 +1,15 @@
<div class="panel panel-default">
<div class="panel-body">
+ <div class="pull-right">
+ {{lang_uptime}}: <b>{{uptime_s}}</b>
+ </div>
<div>
{{lang_sessionTx}}: <b>{{bytesSent_s}}</b>
- ––
+ –
{{lang_sessionRx}}: <b>{{bytesReceived_s}}</b>
- ––
- {{lang_uptime}}: <b>{{uptime_s}}</b>
+ {{#ratio}}
+ &ensp; ({{lang_ratio}}: {{ratio}})
+ {{/ratio}}
</div>
<div>
{{lang_storageSize}}: <b>{{spaceTotal_s}}</b>