diff options
-rw-r--r-- | inc/property.inc.php | 13 | ||||
-rw-r--r-- | inc/taskmanager.inc.php | 40 | ||||
-rw-r--r-- | modules/systemstatus.inc.php | 75 | ||||
-rw-r--r-- | script/circles.min.js | 16 | ||||
-rw-r--r-- | script/custom.js | 37 | ||||
-rw-r--r-- | style/default.css | 8 | ||||
-rw-r--r-- | templates/main-menu.html | 1 | ||||
-rw-r--r-- | templates/systemstatus/_page.html | 13 | ||||
-rw-r--r-- | templates/systemstatus/diskstat.html | 50 |
9 files changed, 218 insertions, 35 deletions
diff --git a/inc/property.inc.php b/inc/property.inc.php index d62bbcb9..00c8018f 100644 --- a/inc/property.inc.php +++ b/inc/property.inc.php @@ -133,6 +133,19 @@ class Property { return json_decode(self::get('vmstore-config'), true); } + public static function getVmStoreUrl() + { + $store = self::getVmStoreConfig(); + if (!isset($store['storetype'])) + return false; + if ($store['storetype'] === 'nfs') + return $store['nfsaddr']; + if ($store['storetype'] === 'cifs') + return $store['cifsaddr']; + if ($store['storetype'] === 'internal') + return '<local>'; + return '<unknown>'; + } public static function setVmStoreConfig($value) { diff --git a/inc/taskmanager.inc.php b/inc/taskmanager.inc.php index 99e35e94..dfacc5a7 100644 --- a/inc/taskmanager.inc.php +++ b/inc/taskmanager.inc.php @@ -18,7 +18,7 @@ class Taskmanager socket_connect(self::$sock, '127.0.0.1', 9215); } - public static function submit($task, $data, $async = false) + public static function submit($task, $data = false, $async = false) { self::init(); $seq = (string) mt_rand(); @@ -67,21 +67,30 @@ class Taskmanager return $reply; } - public static function waitComplete($taskId) + public static function waitComplete($task) { + if (isset($task['id'])) { + if ($task['statusCode'] !== TASK_PROCESSING && $task['statusCode'] !== TASK_WAITING) { + self::release($task['id']); + return $task; + } + $task = $task['id']; + } + if (!is_string($task)) + return false; $done = false; for ($i = 0; $i < 10; ++$i) { - $status = self::status($taskId); + $status = self::status($task); if (!isset($status['statusCode'])) break; - if ($status['statusCode'] != TASK_PROCESSING && $status['statusCode'] != TASK_WAITING) { + if ($status['statusCode'] !== TASK_PROCESSING && $status['statusCode'] !== TASK_WAITING) { $done = true; break; } usleep(150000); } if ($done) - self::release($taskId); + self::release($task); return $status; } @@ -93,6 +102,27 @@ class Taskmanager return true; return false; } + + public static function addErrorMessage($task) + { + static $failure = false; + if ($task === false) { + if (!$failure) { + Message::addError('taskmanager-error'); + $failure = true; + } + return; + } + if (!isset($task['statusCode'])) { + Message::addError('taskmanager-format'); + return; + } + if (isset($task['data']['error'])) { + Message::addError('task-error', $task['statusCode'] . ' (' . $task['data']['error'] . ')'); + return; + } + Message::addError('task-error', $task['statusCode']); + } public static function release($taskId) { diff --git a/modules/systemstatus.inc.php b/modules/systemstatus.inc.php new file mode 100644 index 00000000..c6d45812 --- /dev/null +++ b/modules/systemstatus.inc.php @@ -0,0 +1,75 @@ +<?php + +class Page_SystemStatus extends Page +{ + + protected function doPreprocess() + { + User::load(); + + if (!User::isLoggedIn()) { + Util::redirect('?do=Main'); + } + } + + protected function doRender() + { + Render::addScriptTop('custom'); + Render::addScriptBottom('circles.min'); + Render::addTemplate('systemstatus/_page'); + } + + protected function doAjax() + { + User::load(); + + if (!User::isLoggedIn()) + return; + + $action = 'ajax' . Request::any('action'); + if (method_exists($this, $action)) + $this->$action(); + else + echo "Action $action not known in " . get_class(); + } + + protected function ajaxDiskStat() + { + $task = Taskmanager::submit('DiskStat'); + $task = Taskmanager::waitComplete($task); + + if (!isset($task['data']['list']) || empty($task['data']['list'])) { + Taskmanager::addErrorMessage($task); + Message::renderList(); + return; + } + $store = Property::getVmStoreUrl(); + $storeUsage = false; + $systemUsage = false; + if ($store !== false) { + if ($store === '<local>') + $storePoint = '/'; + else + $storePoint = '/srv/openslx/nfs'; + foreach ($task['data']['list'] as $entry) { + if ($entry['mountPoint'] === $storePoint) + $storeUsage = array( + 'percent' => $entry['usedPercent'], + 'size' => Util::readableFileSize ($entry['sizeKb'] * 1024), + 'color' => dechex(round(($entry['usedPercent'] / 100) * 15)) . dechex(round(((100 - $entry['usedPercent']) / 100) * 15)) . '4' + ); + if ($entry['mountPoint'] === '/') + $systemUsage = array( + 'percent' => $entry['usedPercent'], + 'size' => Util::readableFileSize ($entry['sizeKb'] * 1024), + 'color' => dechex(round(($entry['usedPercent'] / 100) * 15)) . dechex(round(((100 - $entry['usedPercent']) / 100) * 15)) . '4' + ); + } + } + echo Render::parse('systemstatus/diskstat', array( + 'store' => $storeUsage, + 'system' => $systemUsage + )); + } + +} diff --git a/script/circles.min.js b/script/circles.min.js new file mode 100644 index 00000000..7349a408 --- /dev/null +++ b/script/circles.min.js @@ -0,0 +1,16 @@ +/** + * circles - v0.0.5 - 2014-05-30 + * + * Copyright (c) 2014 lugolabs + * Licensed + */ +(function(){var l=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(a){setTimeout(a,1E3/60)},f=window.Circles=function(a){this._el=document.getElementById(a.id);if(null!==this._el){this._radius=a.radius||10;this._duration=void 0===a.duration?500:a.duration;this._value=0;this._maxValue=a.maxValue||100;this._text=void 0===a.text?function(a){return this.htmlifyNumber(a)}:a.text;this._strokeWidth= +a.width||10;this._colors=a.colors||["#EEE","#F00"];this._textContainer=this._wrapContainer=this._movingPath=this._svg=null;this._wrpClass=a.wrpClass||"circles-wrp";this._textClass=a.textClass||"circles-text";var b=Math.PI/180*270;this._start=-Math.PI/180*90;this._startPrecise=this._precise(this._start);this._circ=b-this._start;this._generate().update(a.value||0)}};f.prototype={VERSION:"0.0.5",_generate:function(){this._svgSize=2*this._radius;this._radiusAdjusted=this._radius-this._strokeWidth/2;this._generateSvg()._generateText()._generateWrapper(); +this._el.innerHTML="";this._el.appendChild(this._wrapContainer);return this},_setPercentage:function(a){this._movingPath.setAttribute("d",this._calculatePath(a,!0));this._textContainer.innerHTML=this._getText(this.getValueFromPercent(a))},_generateWrapper:function(){this._wrapContainer=document.createElement("div");this._wrapContainer.className=this._wrpClass;this._wrapContainer.style.position="relative";this._wrapContainer.style.display="inline-block";this._wrapContainer.appendChild(this._svg);this._wrapContainer.appendChild(this._textContainer); +return this},_generateText:function(){this._textContainer=document.createElement("div");this._textContainer.className=this._textClass;var a={position:"absolute",top:0,left:0,textAlign:"center",width:"100%",fontSize:.7*this._radius+"px",height:this._svgSize+"px",lineHeight:this._svgSize+"px"},b;for(b in a)this._textContainer.style[b]=a[b];this._textContainer.innerHTML=this._getText(0);return this},_getText:function(a){if(!this._text)return"";void 0===a&&(a=this._value);a=parseFloat(a.toFixed(2));return"function"=== +typeof this._text?this._text.call(this,a):this._text},_generateSvg:function(){this._svg=document.createElementNS("http://www.w3.org/2000/svg","svg");this._svg.setAttribute("xmlns","http://www.w3.org/2000/svg");this._svg.setAttribute("width",this._svgSize);this._svg.setAttribute("height",this._svgSize);this._generatePath(100,!1,this._colors[0])._generatePath(1,!0,this._colors[1]);this._movingPath=this._svg.getElementsByTagName("path")[1];return this},_generatePath:function(a,b,d){var c=document.createElementNS("http://www.w3.org/2000/svg", +"path");c.setAttribute("fill","transparent");c.setAttribute("stroke",d);c.setAttribute("stroke-width",this._strokeWidth);c.setAttribute("d",this._calculatePath(a,b));this._svg.appendChild(c);return this},_calculatePath:function(a,b){var d=this._precise(this._start+a/100*this._circ);return this._arc(d,b)},_arc:function(a,b){var d=a-.001,c=a-this._startPrecise<Math.PI?0:1;return["M",this._radius+this._radiusAdjusted*Math.cos(this._startPrecise),this._radius+this._radiusAdjusted*Math.sin(this._startPrecise), +"A",this._radiusAdjusted,this._radiusAdjusted,0,c,1,this._radius+this._radiusAdjusted*Math.cos(d),this._radius+this._radiusAdjusted*Math.sin(d),b?"":"Z"].join(" ")},_precise:function(a){return Math.round(1E3*a)/1E3},htmlifyNumber:function(a,b,d){b=b||"circles-integer";d=d||"circles-decimals";a=(a+"").split(".");b='<span class="'+b+'">'+a[0]+"</span>";1<a.length&&(b+='.<span class="'+d+'">'+a[1].substring(0,2)+"</span>");return b},updateRadius:function(a){this._radius=a;return this._generate().update(!0)}, +updateWidth:function(a){this._strokeWidth=a;return this._generate().update(!0)},updateColors:function(a){this._colors=a;var b=this._svg.getElementsByTagName("path");b[0].setAttribute("stroke",a[0]);b[1].setAttribute("stroke",a[1]);return this},getPercent:function(){return 100*this._value/this._maxValue},getValueFromPercent:function(a){return this._maxValue*a/100},getValue:function(){return this._value},getMaxValue:function(){return this._maxValue},update:function(a,b){if(!0===a)return this._setPercentage(this.getPercent()), +this;if(this._value==a||isNaN(a))return this;void 0===b&&(b=this._duration);var d=this,c=d.getPercent(),g=1,e,h,f,k;this._value=Math.min(this._maxValue,Math.max(0,a));if(!b)return this._setPercentage(this.getPercent()),this;e=d.getPercent();h=e>c;g+=e%1;f=Math.floor(Math.abs(e-c)/g);k=b/f;(function m(a){c=h?c+g:c-g;if(h&&c>=e||!h&&c<=e)l(function(){d._setPercentage(e)});else{l(function(){d._setPercentage(c)});var b=Date.now();a=b-a;a>=k?m(b):setTimeout(function(){m(Date.now())},k-a)}})(Date.now()); +return this}};f.create=function(a){return new f(a)}})();
\ No newline at end of file diff --git a/script/custom.js b/script/custom.js index 12e760af..12fe817e 100644 --- a/script/custom.js +++ b/script/custom.js @@ -1,34 +1,11 @@ -/* function loadContent(elem, source) { - $(elem).html('<div class="progress progress-striped active"><div class="progress-bar" style="width:100%"><span class="sr-only">In Progress....</span></div></div>'); - $(elem).load(source); -} - -function selectDir(obj) -{ - dirname = $(obj).parent().parent().find('td.isdir').text() + '/'; - console.log("CALLED! Dirname: " + dirname); - $('td.fileEntry').each(function() { - var text = $(this).text(); - if (text.length < dirname.length) return; - if (text.substr(0, dirname.length) !== dirname) return; - $(this).parent().find('.fileBox')[0].checked = obj.checked; - }); -} -*/ - -function updater(url, postdata, callback) -{ - var updateTimer = setInterval(function () { - if (typeof $ === 'undefined') + var waitForIt = function() { + if (typeof $ === 'undefined') { + setTimeout(waitForIt, 50); return; - $.post(url, postdata, function (data, status) { - if (!callback(data, status)) - clearInterval(updateTimer); - }, 'json').fail(function (jqXHR, textStatus, errorThrown) { - if (!callback(errorThrown, textStatus)) - clearInterval(updateTimer); - }); - }, 1000); + } + $(elem).load(source); + } + waitForIt(); } diff --git a/style/default.css b/style/default.css index 813e54c2..1cac5ee7 100644 --- a/style/default.css +++ b/style/default.css @@ -103,3 +103,11 @@ body { .slx-md-width { max-width: 600px; } + +.slx-storechart { + max-width: 140px; + margin: 5px; + padding: 3px; + float: left; + background-color: #eee; +} diff --git a/templates/main-menu.html b/templates/main-menu.html index 50fdd211..06c3ed6b 100644 --- a/templates/main-menu.html +++ b/templates/main-menu.html @@ -27,6 +27,7 @@ </ul> </li> <li><a href="?do=News">News</a></li> + <li><a href="?do=SystemStatus">Status</a></li> </ul> <ul class="nav navbar-nav navbar-right"> {{{loginPanel}}} diff --git a/templates/systemstatus/_page.html b/templates/systemstatus/_page.html new file mode 100644 index 00000000..5b1ab375 --- /dev/null +++ b/templates/systemstatus/_page.html @@ -0,0 +1,13 @@ +<div class="container"> + <div class="panel panel-default"> + <div class="panel-heading"> + Speicherplatz + </div> + <div class="panel-body" id="diskstat"> + *dreh dreh dreh dreh* + </div> + </div> +</div> +<script type="text/javascript"> + loadContent('#diskstat', '?do=SystemStatus&action=DiskStat'); +</script> diff --git a/templates/systemstatus/diskstat.html b/templates/systemstatus/diskstat.html new file mode 100644 index 00000000..e1d4a57e --- /dev/null +++ b/templates/systemstatus/diskstat.html @@ -0,0 +1,50 @@ +<div class="slx-storechart"> + {{#system}} + <b>Systempartition</b> + <div id="circles-system"></div> + Kapazität: {{size}} + {{/system}} + {{^system}} + <b>Fehler beim Ermitteln des verfügbaren Speichers auf der Systempartition!</b> + {{/system}} +</div> +<div class="slx-storechart"> + {{#store}} + <b>VM-Speicher</b> + <div id="circles-store"></div> + Kapazität: {{size}} + {{/store}} + {{^store}} + <b>Fehler beim Ermitteln des verfügbaren Speicherplatzes am VM-Speicherort. Bitte überprüfen Sie die Konfiguration.</b> + {{/store}} +</div> +<script type="text/javascript"> + {{#store}} + Circles.create({ + id: 'circles-store', + radius: 60, + value: {{{percent}}}, + maxValue: 100, + width: 10, + text: function(value){return value + '%'; }, + colors: ['#D3B6C6', '#{{color}}'], + duration: 400, + wrpClass: 'circles-wrp', + textClass: 'circles-text' + }); + {{/store}} + {{#system}} + Circles.create({ + id: 'circles-system', + radius: 60, + value: {{{percent}}}, + maxValue: 100, + width: 10, + text: function(value){return value + '%'; }, + colors: ['#D3B6C6', '#{{color}}'], + duration: 400, + wrpClass: 'circles-wrp', + textClass: 'circles-text' + }); + {{/system}} +</script>
\ No newline at end of file |