summaryrefslogtreecommitdiffstats
path: root/modules-available/dnbd3/page.inc.php
diff options
context:
space:
mode:
Diffstat (limited to 'modules-available/dnbd3/page.inc.php')
-rw-r--r--modules-available/dnbd3/page.inc.php417
1 files changed, 417 insertions, 0 deletions
diff --git a/modules-available/dnbd3/page.inc.php b/modules-available/dnbd3/page.inc.php
new file mode 100644
index 00000000..2836cbf4
--- /dev/null
+++ b/modules-available/dnbd3/page.inc.php
@@ -0,0 +1,417 @@
+<?php
+
+class Page_Dnbd3 extends Page
+{
+
+ protected function doPreprocess()
+ {
+ User::load();
+
+ if (!User::isLoggedIn()) {
+ Message::addError('main.no-permission');
+ Util::redirect('?do=Main');
+ }
+ $action = Request::post('action', false, 'string');
+ if ($action === 'refresh') {
+ Dnbd3Util::updateServerStatus();
+ } elseif ($action === 'delserver') {
+ $this->deleteServer();
+ } elseif ($action === 'addserver') {
+ $this->addServer();
+ } elseif ($action === 'editserver') {
+ $this->editServer();
+ } elseif ($action === 'savelocations') {
+ $this->saveServerLocations();
+ } elseif ($action === 'toggle-usage') {
+ $this->toggleUsage();
+ }
+ if (Request::isPost()) {
+ Util::redirect('?do=dnbd3');
+ }
+ }
+
+ private function editServer()
+ {
+ $server = $this->getServerById();
+ if (!isset($server['machineuuid'])) {
+ Message::addError('not-automatic-server', $server['ip']);
+ return;
+ }
+ $bgr = Request::post('bgr', false, 'bool');
+ $firewall = Request::post('firewall', false, 'bool');
+ RunMode::setRunMode($server['machineuuid'], 'dnbd3', 'proxy',
+ json_encode(compact('bgr', 'firewall')), false);
+ }
+
+ private function toggleUsage()
+ {
+ $enabled = Request::post('enabled', false, 'bool');
+ $nfs = Request::post('with-nfs', false, 'bool');
+ $task = Dnbd3::setEnabled($enabled);
+ Dnbd3::setNfsFallback($nfs);
+ Taskmanager::waitComplete($task, 5000);
+ }
+
+ private function saveServerLocations()
+ {
+ $server = $this->getServerById();
+ $locids = Request::post('location', [], 'array');
+ if (empty($locids)) {
+ Database::exec('DELETE FROM dnbd3_server_x_location WHERE serverid = :serverid',
+ array('serverid' => $server['serverid']));
+ } else {
+ Database::exec('DELETE FROM dnbd3_server_x_location WHERE serverid = :serverid AND locationid NOT IN (:lids)',
+ array('serverid' => $server['serverid'], 'lids' => $locids));
+ foreach ($locids as $lid) {
+ Database::exec('INSERT IGNORE INTO dnbd3_server_x_location (serverid, locationid) VALUES (:serverid, :lid)',
+ array('serverid' => $server['serverid'], 'lid' => $lid));
+ }
+ }
+ }
+
+ private function addServer()
+ {
+ $ip = Request::post('newip', false, 'string');
+ if ($ip === false) {
+ Message::addError('main.parameter-missing', 'ip');
+ return;
+ }
+ $ip = ip2long(trim($ip));
+ if ($ip !== false) {
+ $ip = long2ip($ip);
+ }
+ if ($ip === false) {
+ Message::addError('invalid-ipv4', $ip);
+ return;
+ }
+ $res = Database::queryFirst('SELECT serverid FROM dnbd3_server s
+ LEFT JOIN machine m USING (machineuuid)
+ WHERE s.fixedip = :ip OR m.clientip = :ip', compact('ip'));
+ if ($res !== false) {
+ Message::addError('server-already-exists', $ip);
+ return;
+ }
+ Database::exec('INSERT INTO dnbd3_server (fixedip) VALUES (:ip)', compact('ip'));
+ Message::addSuccess('server-added', $ip);
+ }
+
+ private function deleteServer()
+ {
+ $server = $this->getServerById();
+ if ($server['fixedip'] === '<self>')
+ return;
+ if (!is_null($server['machineuuid'])) {
+ RunMode::setRunMode($server['machineuuid'], 'dnbd3', null, null, null);
+ }
+ Database::exec('DELETE FROM dnbd3_server WHERE serverid = :serverid',
+ array('serverid' => $server['serverid']));
+ Message::addSuccess('server-deleted', $server['ip']);
+ }
+
+ /*
+ * RENDER
+ */
+
+ protected function doRender()
+ {
+ $show = Request::get('show', false, 'string');
+ if ($show === 'proxy') {
+ $this->showProxyDetails();
+ } elseif ($show === 'locations') {
+ $this->showServerLocationEdit();
+ } elseif ($show === false) {
+ $this->showServerList();
+ } else {
+ Util::redirect('?do=dnbd3');
+ }
+ }
+
+ private function showServerList()
+ {
+ $dynClients = RunMode::getForMode(Page::getModule(), 'proxy', true, true);
+ $res = Database::simpleQuery('SELECT s.serverid, s.machineuuid, s.fixedip, s.lastseen AS dnbd3lastseen,
+ s.uptime, s.totalup, s.totaldown, s.clientcount, s.disktotal, s.diskfree, Count(sxl.locationid) AS locations,
+ s.errormsg
+ FROM dnbd3_server s
+ LEFT JOIN dnbd3_server_x_location sxl USING (serverid)
+ GROUP BY s.serverid');
+ $servers = array();
+ $sort = array();
+ $NOW = time();
+ while ($server = $res->fetch(PDO::FETCH_ASSOC)) {
+ if (isset($dynClients[$server['machineuuid']])) {
+ $server += $dynClients[$server['machineuuid']];
+ unset($dynClients[$server['machineuuid']]);
+ }
+ if ($server['uptime'] != 0) {
+ $server['uptime'] += ($NOW - $server['dnbd3lastseen']);
+ }
+ $server['dnbd3lastseen_s'] = $server['dnbd3lastseen'] ? date('d.m.Y H:i', $server['dnbd3lastseen']) : '-';
+ $server['uptime_s'] = $server['uptime'] ? floor($server['uptime'] / 86400) . 'd ' . gmdate('H:i', $server['uptime']) : '-';
+ $server['totalup_s'] = Util::readableFileSize($server['totalup']);
+ $server['totaldown_s'] = Util::readableFileSize($server['totaldown']);
+ if ($server['disktotal'] > 0) {
+ $server['disktotal_s'] = Util::readableFileSize($server['disktotal']);
+ $server['diskfree_s'] = Util::readableFileSize($server['diskfree']);
+ $server['diskUsePercent'] = floor(100 - 100 * $server['diskfree'] / $server['disktotal']);
+ } else {
+ $server['disktotal_s'] = '?';
+ $server['diskfree_s'] = '?';
+ $server['diskUsePercent'] = 0;
+ }
+ $server['self'] = ($server['fixedip'] === '<self>');
+ if (isset($server['clientip']) && !is_null($server['clientip'])) {
+ if ($NOW - $server['lastseen'] > 360) {
+ $server['slxDown'] = true;
+ } else {
+ $server['slxOk'] = true;
+ }
+ }
+ if ($server['self']) {
+ $sort[] = '---';
+ } else {
+ $sort[] = $server['fixedip'] . '.' . $server['machineuuid'];
+ }
+ $servers[] = $server;
+ }
+ foreach ($dynClients as $server) {
+ $servers[] = $server;
+ $sort[] = '-' . $server['machineuuid'];
+ Database::exec('INSERT INTO dnbd3_server (machineuuid) VALUES (:uuid)', array('uuid' => $server['machineuuid']));
+ }
+ array_multisort($sort, SORT_ASC, $servers);
+ Render::addTemplate('page-serverlist', array(
+ 'list' => $servers,
+ 'enabled' => Dnbd3::isEnabled(),
+ 'enabled_checked_s' => Dnbd3::isEnabled() ? 'checked' : '',
+ 'nfs_checked_s' => Dnbd3::hasNfsFallback() ? 'checked' : '',
+ 'rebootcontrol' => Module::isAvailable('rebootcontrol', false)
+ ));
+ }
+
+ private function showProxyDetails()
+ {
+ $server = $this->getServerById();
+ Render::addTemplate('page-proxy-header', $server);
+ $stats = Dnbd3Rpc::query($server['ip'], 5003,true, true, false, true);
+ if (!is_array($stats) || !isset($stats['runId'])) {
+ Message::addError('server-unreachable');
+ return;
+ }
+ $stats['bytesSent_s'] = Util::readableFileSize($stats['bytesSent']);
+ $stats['bytesReceived_s'] = Util::readableFileSize($stats['bytesReceived']);
+ $stats['uptime_s'] = floor($stats['uptime'] / 86400) . 'd ' . gmdate('H:i:s', $stats['uptime']);
+ Render::addTemplate('page-proxy-stats', $stats);
+ $images = Dnbd3Rpc::query($server['ip'], 5003,false, false, true);
+ $confAlts = Dnbd3Rpc::query($server['ip'], 5003,false, false, false, false, true, true);
+ $ips = array();
+ $sort = array();
+ foreach ($stats['clients'] as &$c) {
+ $c['bytesSent_s'] = Util::readableFileSize($c['bytesSent']);
+ $sort[] = $c['bytesSent'];
+ $ips[] = preg_replace('/:\d+$/', '', $c['address']);
+ }
+ array_multisort($sort, SORT_DESC, $stats['clients']);
+ Render::openTag('div', ['class' => 'row']);
+ // Config
+ if (is_string($confAlts['config'])) {
+ Render::addTemplate('page-proxy-config', $confAlts);
+ }
+ if (is_array($confAlts['altservers'])) {
+ foreach ($confAlts['altservers'] as &$as) {
+ $as['rtt'] = round(array_sum($as['rtt']) / count($as['rtt']) / 1000, 2);
+ }
+ unset($as);
+ Render::addTemplate('page-proxy-altservers', $confAlts);
+ }
+ Render::closeTag('div');
+ Render::openTag('div', ['class' => 'row']);
+ // Count locations
+ $res = Database::simpleQuery('SELECT locationid, Count(*) AS cnt FROM machine WHERE clientip IN (:ips) GROUP BY locationid', compact('ips'));
+ $locCount = Location::getLocationsAssoc();
+ $locCount[0] = array(
+ 'locationname' => '/',
+ 'depth' => 0,
+ 'recCount' => 0,
+ );
+ foreach ($locCount as &$loc) {
+ $loc['recCount'] = 0;
+ }
+ $showLocs = false;
+ while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ settype($row['locationid'], 'int');
+ $loc =& $locCount[$row['locationid']];
+ $loc['clientCount'] = $row['cnt'];
+ $loc['recCount'] += $row['cnt'];
+ if ($row['locationid'] !== 0) {
+ $showLocs = true;
+ }
+ $loc['keep'] = true;
+ if (isset($loc['parents'])) {
+ foreach ($loc['parents'] as $p) {
+ $locCount[$p]['keep'] = true;
+ $locCount[$p]['recCount'] += $row['cnt'];
+ }
+ }
+ }
+ if ($showLocs) {
+ $locCount = array_filter($locCount, function ($v) { return isset($v['keep']); });
+ Render::addTemplate('page-proxy-loclist', array('list' => array_values($locCount)));
+ }
+ Render::addTemplate('page-proxy-clients', $stats);
+ Render::closeTag('div');
+ }
+
+ private function showServerLocationEdit()
+ {
+ $server = $this->getServerById();
+ // Get selected ones
+ $res = Database::simpleQuery('SELECT locationid FROM dnbd3_server_x_location WHERE serverid = :serverid',
+ array('serverid' => $server['serverid']));
+ $selectedLocations = array();
+ while ($loc = $res->fetchColumn(0)) {
+ $selectedLocations[$loc] = true;
+ }
+ // Build location list
+ $server['locations'] = array_values(Location::getSubnetsByLocation());
+ $filtered = array();
+ foreach ($server['locations'] as &$loc) {
+ $filtered['l'.$loc['locationid']] = array(
+ 'children' => $loc['children'],
+ 'subnets' => $loc['subnets']
+ );
+ if (isset($selectedLocations[$loc['locationid']])) {
+ $loc['checked_s'] = 'checked';
+ }
+ }
+ unset($loc);
+ $server['jsonLocations'] = json_encode($filtered);
+ Render::addTemplate('page-server-locations', $server);
+ }
+
+ private function getServerById($serverId = false)
+ {
+ if ($serverId === false) {
+ $serverId = Request::any('server', false, 'int');
+ }
+ if ($serverId === false) {
+ if (AJAX)
+ die('Missing parameter');
+ Message::addError('main.parameter-missing', 'server');
+ Util::redirect('?do=dnbd3');
+ }
+ $server = Database::queryFirst('SELECT s.serverid, s.machineuuid, s.fixedip, m.clientip, m.hostname
+ FROM dnbd3_server s
+ LEFT JOIN machine m USING (machineuuid)
+ WHERE s.serverid = :serverId', compact('serverId'));
+ if ($server === false) {
+ if (AJAX)
+ die('Invalid server id');
+ Message::addError('server-non-existent', 'server');
+ Util::redirect('?do=dnbd3');
+ }
+ if (!is_null($server['clientip'])) {
+ $server['ip'] = $server['clientip'];
+ } elseif (!is_null($server['fixedip'])) {
+ $server['ip'] = $server['fixedip'];
+ } else {
+ $server['ip'] = '127.0.0.1';
+ }
+ return $server;
+ }
+
+ /*
+ * AJAX
+ */
+
+ protected function doAjax()
+ {
+ User::load();
+ if (!User::isLoggedIn())
+ die('No');
+ $action = Request::any('action', false, 'string');
+ if ($action === 'servertest') {
+ $this->ajaxServerTest();
+ } elseif ($action === 'editserver') {
+ $this->ajaxEditServer();
+ } elseif ($action === 'reboot') {
+ $this->ajaxReboot();
+ } else {
+ die($action . '???');
+ }
+ }
+
+ private function ajaxServerTest()
+ {
+ Header('Content-Type: application/json; charset=utf-8');
+ $ip = Request::post('ip', false, 'string');
+ if ($ip === false)
+ die('{"error": "Missing parameter", "fatal": true}');
+ $ip = ip2long(trim($ip));
+ if ($ip !== false) {
+ $ip = long2ip($ip);
+ }
+ if ($ip === false)
+ die('{"error": "Supports IPv4 only", "fatal": true}');
+ // Dup?
+ $res = Database::queryFirst('SELECT serverid FROM dnbd3_server s
+ LEFT JOIN machine m USING (machineuuid)
+ WHERE s.fixedip = :ip OR m.clientip = :ip', compact('ip'));
+ if ($res !== false)
+ die('{"error": "Server with this IP already exists", "fatal": true}');
+ // Query
+ $reply = Dnbd3Rpc::query($ip, 5003,true, false, false, true);
+ if ($reply === Dnbd3Rpc::QUERY_UNREACHABLE)
+ die('{"error": "Could not reach server"}');
+ if ($reply === Dnbd3Rpc::QUERY_NOT_200)
+ die('{"error": "Server did not reply with 200 OK"}');
+ if ($reply === Dnbd3Rpc::QUERY_NOT_JSON)
+ die('{"error": "No JSON received from server"}');
+ if (!is_array($reply) || !isset($reply['uptime']) || !isset($reply['clientCount']))
+ die('{"error": "Reply does not suggest this is a dnbd3 server"}');
+ echo json_encode($reply);
+ }
+
+ private function ajaxEditServer()
+ {
+ $server = $this->getServerById();
+ if (!isset($server['machineuuid'])) {
+ echo 'Not automatic server.';
+ return;
+ }
+ $rm = RunMode::getForMode(Page::getModule(), 'proxy', false, true);
+ if (!isset($rm[$server['machineuuid']])) {
+ echo 'Error: RunMode entry missing.';
+ return;
+ }
+ $modeData = (array)json_decode($rm[$server['machineuuid']]['modedata'], true);
+ $server += $modeData + Dnbd3Util::defaultRunmodeConfig();
+ echo Render::parse('fragment-server-settings', $server);
+ }
+
+ private function ajaxReboot()
+ {
+ $server = $this->getServerById();
+ if (!isset($server['machineuuid'])) {
+ die('Not automatic server.');
+ }
+ if (!Module::isAvailable('rebootcontrol')) {
+ die('No rebootcontrol');
+ }
+ $uuid = $server['machineuuid'];
+ $task = RebootControl::reboot([ $uuid ]);
+ if ($task === false) {
+ die('Taskmanager unreachable');
+ }
+ $task = Taskmanager::waitComplete($task, 2000);
+ if (is_array($task) && isset($task['data']) && isset($task['data']['clientStatus']) && isset($task['data']['clientStatus'][$uuid])) {
+ $status = $task['data']['clientStatus'][$uuid];
+ if (!empty($task['data']['error'])) {
+ $status .= "\n --- \n" . $task['data']['error'];
+ }
+ die($status);
+ }
+ die('Unknown :-(');
+ }
+
+}