diff options
-rw-r--r-- | api.php | 16 | ||||
-rw-r--r-- | apis/getconfig.inc.php | 17 | ||||
-rw-r--r-- | apis/init.inc.php | 7 | ||||
-rw-r--r-- | apis/taskmanager.inc.php | 10 | ||||
-rw-r--r-- | config.php | 3 | ||||
-rw-r--r-- | inc/property.inc.php | 47 | ||||
-rw-r--r-- | inc/render.inc.php | 1 | ||||
-rw-r--r-- | inc/taskmanager.inc.php | 41 | ||||
-rw-r--r-- | inc/trigger.inc.php | 40 | ||||
-rw-r--r-- | index.php | 2 | ||||
-rw-r--r-- | modules/main.inc.php | 9 | ||||
-rw-r--r-- | modules/minilinux.inc.php | 73 | ||||
-rw-r--r-- | modules/sysconfig.inc.php | 1 | ||||
-rw-r--r-- | modules/vmstore.inc.php | 72 | ||||
-rw-r--r-- | script/taskmanager.js | 33 | ||||
-rw-r--r-- | style/default.css | 7 | ||||
-rw-r--r-- | templates/main-menu.html | 1 | ||||
-rw-r--r-- | templates/minilinux/download.html | 1 | ||||
-rw-r--r-- | templates/minilinux/filelist.html | 39 | ||||
-rw-r--r-- | templates/page-main.html | 6 | ||||
-rw-r--r-- | templates/page-minilinux.html | 39 | ||||
-rw-r--r-- | templates/page-vmstore.html | 89 | ||||
-rw-r--r-- | templates/vmstore/mount.html | 28 |
23 files changed, 511 insertions, 71 deletions
@@ -2,12 +2,16 @@ error_reporting(E_ALL); -require_once('inc/user.inc.php'); -require_once('inc/util.inc.php'); -require_once('inc/database.inc.php'); -require_once('inc/permission.inc.php'); -require_once('inc/crypto.inc.php'); -require_once('inc/validator.inc.php'); +require_once 'config.php'; + +// Autoload classes from ./inc which adhere to naming scheme <lowercasename>.inc.php +function slxAutoloader($class) { + $file = 'inc/' . preg_replace('/[^a-z0-9]/', '', mb_strtolower($class)) . '.inc.php'; + if (!file_exists($file)) return; + require_once $file; +} +spl_autoload_register('slxAutoloader'); + if (empty($_REQUEST['do'])) { // No specific module - set default diff --git a/apis/getconfig.inc.php b/apis/getconfig.inc.php index 1e7a4f53..f29118c8 100644 --- a/apis/getconfig.inc.php +++ b/apis/getconfig.inc.php @@ -1,5 +1,7 @@ <?php +require_once 'inc/property.inc.php'; + // Dump config from DB $res = Database::simpleQuery('SELECT setting.setting, setting.defaultvalue, setting.permissions, setting.description, tbl.value FROM setting @@ -12,3 +14,18 @@ while ($row = $res->fetch(PDO::FETCH_ASSOC)) { // Additional "intelligent" config echo "SLX_REMOTE_LOG='http://${_SERVER['SERVER_ADDR']}/slxadmin/api.php?do=clientlog'\n"; +$vmstore = Property::getVmStoreConfig(); + +if (is_array($vmstore)) { + switch ($vmstore['storetype']) { + case 'internal'; + echo "SLX_VM_NFS='{$_SERVER['SERVER_ADDR']}:/srv/openslx/nfs'\n"; + break; + case 'nfs'; + echo "SLX_VM_NFS='{$vmstore['nfsaddr']}'\n"; + break; + case 'cifs'; + echo "SLX_VM_NFS='{$vmstore['cifsaddr']}'\n"; + break; + } +} diff --git a/apis/init.inc.php b/apis/init.inc.php new file mode 100644 index 00000000..cdd6ac05 --- /dev/null +++ b/apis/init.inc.php @@ -0,0 +1,7 @@ +<?php + +if ($_SERVER['REMOTE_ADDR'] !== '127.0.0.1') + exit(0); + +Trigger::ldadp(); +Trigger::mount(); diff --git a/apis/taskmanager.inc.php b/apis/taskmanager.inc.php index 78cd101c..7bb38a98 100644 --- a/apis/taskmanager.inc.php +++ b/apis/taskmanager.inc.php @@ -16,11 +16,15 @@ foreach ($_POST['ids'] as $id) { } $return[] = $status; // HACK HACK - should be pluggable - if (isset($status['statusCode']) && $status['statusCode'] === TASK_FINISHED - && $status['id'] === Property::getIPxeTaskId() && Property::getServerIp() !== Property::getIPxeIp()) { + if (isset($status['statusCode']) && $status['statusCode'] === TASK_FINISHED // iPXE Update + && $id === Property::getIPxeTaskId() && Property::getServerIp() !== Property::getIPxeIp()) { Property::setIPxeIp(Property::getServerIp()); } - // + if (isset($status['statusCode']) && $status['statusCode'] === TASK_FINISHED // MiniLinux Version check + && $id === Property::getVersionCheckTaskId()) { + Property::setVersionCheckInformation(Property::getServerIp()); + } + // -- END HACKS -- if (!isset($status['statusCode']) || ($status['statusCode'] !== TASK_WAITING && $status['statusCode'] !== TASK_PROCESSING)) { Taskmanager::release($id); } @@ -15,8 +15,7 @@ define('CONFIG_SQL_PASS', 'geheim'); define('CONFIG_TGZ_LIST_DIR', '/opt/openslx/configs'); -define('CONFIG_REMOTE_TGZ', 'http://mltk.boot.openslx.org/tgz'); -define('CONFIG_REMOTE_ML', 'http://mltk.boot.openslx.org/update'); +define('CONFIG_REMOTE_ML', 'http://mltk.boot.openslx.org/update/new'); define('CONFIG_TFTP_DIR', '/srv/openslx/tftp'); define('CONFIG_HTTP_DIR', '/srv/openslx/www/boot'); diff --git a/inc/property.inc.php b/inc/property.inc.php index d186193a..5c316517 100644 --- a/inc/property.inc.php +++ b/inc/property.inc.php @@ -84,5 +84,52 @@ class Property { self::set('ipxe-menu', json_encode($value)); } + + public static function getVersionCheckTaskId() + { + return self::get('versioncheck-task'); + } + + public static function setVersionCheckTaskId($value) + { + self::set('versioncheck-task', $value); + } + + public static function getVersionCheckInformation() + { + $data = json_decode(self::get('versioncheck-data'), true); + if (isset($data['time']) && $data['time'] + 120 > time()) + return $data; + $task = Taskmanager::submit('DownloadText', array( + 'url' => CONFIG_REMOTE_ML . '/list.php' + )); + if (!isset($task['id'])) + return false; + if ($task['statusCode'] !== TASK_FINISHED) { + $task = Taskmanager::waitComplete($task['id']); + } + if ($task['statusCode'] !== TASK_FINISHED || !isset($task['data']['content'])) { + return $task['data']['error']; + } + $data = json_decode($task['data']['content'], true); + $data['time'] = time(); + self::setVersionCheckInformation($data); + return $data; + } + + public static function setVersionCheckInformation($value) + { + self::set('versioncheck-data', json_encode($value)); + } + + public static function getVmStoreConfig() + { + return json_decode(self::get('vmstore-config'), true); + } + + public static function setVmStoreConfig($value) + { + self::set('vmstore-config', json_encode($value)); + } } diff --git a/inc/render.inc.php b/inc/render.inc.php index cf0958c2..6853acde 100644 --- a/inc/render.inc.php +++ b/inc/render.inc.php @@ -48,7 +48,6 @@ class Render <script type="text/javascript"> var TOKEN = "' . Session::get('token') . '"; </script> - </body> ', self::$header , diff --git a/inc/taskmanager.inc.php b/inc/taskmanager.inc.php index e93cc696..99e35e94 100644 --- a/inc/taskmanager.inc.php +++ b/inc/taskmanager.inc.php @@ -5,12 +5,13 @@ */ class Taskmanager { - + private static $sock = false; - + private static function init() { - if (self::$sock !== false) return; + if (self::$sock !== false) + return; self::$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); socket_set_option(self::$sock, SOL_SOCKET, SO_RCVTIMEO, array('sec' => 0, 'usec' => 300000)); socket_set_option(self::$sock, SOL_SOCKET, SO_SNDTIMEO, array('sec' => 0, 'usec' => 200000)); @@ -20,7 +21,7 @@ class Taskmanager public static function submit($task, $data, $async = false) { self::init(); - $seq = (string)mt_rand(); + $seq = (string) mt_rand(); if (empty($data)) { $data = '{}'; } else { @@ -32,7 +33,8 @@ class Taskmanager Message::addError('taskmanager-error'); return false; } - if ($async) return true; + if ($async) + return true; $reply = self::readReply($seq); if ($reply === false) { Message::addError('taskmanager-error'); @@ -56,38 +58,50 @@ class Taskmanager public static function status($taskId) { self::init(); - $seq = (string)mt_rand(); + $seq = (string) mt_rand(); $message = "$seq, status, $taskId"; $sent = socket_send(self::$sock, $message, strlen($message), 0); $reply = self::readReply($seq); - if (!is_array($reply)) return false; + if (!is_array($reply)) + return false; return $reply; } - + public static function waitComplete($taskId) { $done = false; for ($i = 0; $i < 10; ++$i) { $status = self::status($taskId); - if (!isset($status['statusCode'])) break; + if (!isset($status['statusCode'])) + break; if ($status['statusCode'] != TASK_PROCESSING && $status['statusCode'] != TASK_WAITING) { $done = true; break; } usleep(150000); } - if ($done) self::release ($taskId); + if ($done) + self::release($taskId); return $status; } + public static function isFailed($task) + { + if (!isset($task['statusCode']) || !isset($task['id'])) + return true; + if ($task['statusCode'] !== TASK_WAITING && $task['statusCode'] !== TASK_PROCESSING && $task['statusCode'] !== TASK_FINISHED) + return true; + return false; + } + public static function release($taskId) { self::init(); - $seq = (string)mt_rand(); + $seq = (string) mt_rand(); $message = "$seq, release, $taskId"; socket_send(self::$sock, $message, strlen($message), 0); } - + /** * * @param type $seq @@ -101,7 +115,8 @@ class Taskmanager if (count($parts) == 2 && $parts[0] == $seq) { return json_decode($parts[1], true); } - if (++$tries > 10) return false; + if (++$tries > 10) + return false; } //error_log(socket_strerror(socket_last_error(self::$sock))); return false; diff --git a/inc/trigger.inc.php b/inc/trigger.inc.php index af12955f..102f7987 100644 --- a/inc/trigger.inc.php +++ b/inc/trigger.inc.php @@ -36,5 +36,43 @@ class Trigger Property::setIPxeTaskId($task['id']); return $task['id']; } + + public static function ldadp() + { + $res = Database::simpleQuery("SELECT moduleid, filepath FROM configtgz_module" + . " INNER JOIN configtgz_x_module USING (moduleid)" + . " INNER JOIN configtgz USING (configid)" + . " WHERE moduletype = 'AD_AUTH'"); + // TODO: Multiconfig support + $id = array(); + while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + if (readlink('/srv/openslx/www/boot/default/config.tgz') === $row['filepath']) { + $id[] = (int)$row['moduleid']; + break; + } + } + $task = Taskmanager::submit('LdadpLauncher', array( + 'ids' => $id + )); + if (!isset($task['id'])) + return false; + return $task['id']; + } + + public static function mount() + { + $vmstore = Property::getVmStoreConfig(); + if (!is_array($vmstore)) return; + $storetype = $vmstore['storetype']; + if ($storetype === 'nfs') $addr = $vmstore['nfsaddr']; + if ($storetype === 'cifs') $addr = $vmstore['nfsaddr']; + if ($storetype === 'internal') $addr = 'none'; + $this->mountTask = Taskmanager::submit('MountVmStore', array( + 'address' => $addr, + 'type' => 'images', + 'username' => $vmstore['cifsuser'], + 'password' => $vmstore['cifspasswd'] + )); + } -}
\ No newline at end of file +} @@ -1,5 +1,7 @@ <?php +require_once 'config.php'; + /** * Page class which all "modules" must be extending from */ diff --git a/modules/main.inc.php b/modules/main.inc.php index ddbc37a4..232d6a0a 100644 --- a/modules/main.inc.php +++ b/modules/main.inc.php @@ -20,7 +20,14 @@ class Page_Main extends Page $ipxe = (Property::getServerIp() !== Property::getIPxeIp()); $sysconfig = !file_exists(CONFIG_HTTP_DIR . '/default/config.tgz'); $minilinux = !file_exists(CONFIG_HTTP_DIR . '/default/kernel') || !file_exists(CONFIG_HTTP_DIR . '/default/initramfs-stage31') || !file_exists(CONFIG_HTTP_DIR . '/default/stage32.sqfs'); - Render::addTemplate('page-main', array('user' => User::getName(), 'ipxe' => $ipxe, 'sysconfig' => $sysconfig, 'minilinux' => $minilinux)); + $vmstore = !is_array(Property::getVmStoreConfig()); + Render::addTemplate('page-main', array( + 'user' => User::getName(), + 'ipxe' => $ipxe, + 'sysconfig' => $sysconfig, + 'minilinux' => $minilinux, + 'vmstore' => $vmstore + )); } } diff --git a/modules/minilinux.inc.php b/modules/minilinux.inc.php index 6e68a34e..e2d85247 100644 --- a/modules/minilinux.inc.php +++ b/modules/minilinux.inc.php @@ -15,18 +15,73 @@ class Page_MiniLinux extends Page protected function doRender() { - $files = array(); - mkdir(CONFIG_HTTP_DIR . "/default", 0755, true); - $this->checkFile($files, 'kernel'); - $this->checkFile($files, 'initramfs-stage31'); - $this->checkFile($files, 'stage32.sqfs'); - $this->checkFile($files, 'vmware.sqfs'); - $this->checkFile($files, 'nvidia_libs.sqfs'); Render::addTemplate('page-minilinux', array( - 'files' => $files, - 'token' => Session::get('token') + 'listurl' => '?do=MiniLinux&async=true&action=list' )); } + + protected function doAjax() + { + $data = Property::getVersionCheckInformation(); + if (!is_array($data) || !isset($data['systems'])) { + echo Render::parse('messagebox-error', array( + 'message' => 'Fehler beim Abrufen der Liste: ' . $data + )); + return; + } + $action = Request::any('action'); + switch ($action) { + case 'list': + $count = 0; + foreach ($data['systems'] as &$system) { + foreach ($system['files'] as &$file) { + $file['uid'] = 'dlid' . $count++; + $local = CONFIG_HTTP_DIR . '/' . $system['id'] . '/' . $file['name']; + if (!file_exists($local) || md5_file($local) !== substr($file['md5'], 0, 32)) { + $file['changed'] = true; + } + } + } + echo Render::parse('minilinux/filelist', array( + 'systems' => $data['systems'], + 'token' => Session::get('token') + )); + return; + case 'download': + $id = Request::post('id'); + $name = Request::post('name'); + if (!$id || !$name || strpos("$id$name", '/') !== false) { + echo "Invalid download request"; + return; + } + $found = false; + foreach ($data['systems'] as &$system) { + if ($system['id'] !== $id) continue; + foreach ($system['files'] as &$file) { + if ($file['name'] !== $name) continue; + $found = true; + break; + } + } + if (!$found) { + echo "Nonexistent system/file: $id / $name"; + return; + } + $task = Taskmanager::submit('DownloadFile', array( + 'url' => CONFIG_REMOTE_ML . '/' . $id . '/' . $name, + 'destination' => CONFIG_HTTP_DIR . '/' . $id . '/' . $name + )); + if (!isset($task['id'])) { + echo 'Error launching download task: ' . $task['statusCode']; + return; + } + echo Render::parse('minilinux/download', array( + 'name' => $name, + 'task' => $task['id'] + )); + return; + } + } private function checkFile(&$files, $name) { diff --git a/modules/sysconfig.inc.php b/modules/sysconfig.inc.php index ebccf036..06ceb618 100644 --- a/modules/sysconfig.inc.php +++ b/modules/sysconfig.inc.php @@ -119,6 +119,7 @@ class Page_SysConfig extends Page Message::addError('task-error', $task['data']['error']); } elseif ($task['statusCode'] === TASK_FINISHED) { Message::addSuccess('config-activated', $row['title']); + Trigger::ldadp(); // TODO: Feedback } Util::redirect('?do=SysConfig'); } diff --git a/modules/vmstore.inc.php b/modules/vmstore.inc.php new file mode 100644 index 00000000..ab06b1af --- /dev/null +++ b/modules/vmstore.inc.php @@ -0,0 +1,72 @@ +<?php + +class Page_VmStore extends Page +{ + private $mountTask = false; + + protected function doPreprocess() + { + User::load(); + + if (!User::hasPermission('superadmin')) { + Message::addError('no-permission'); + Util::redirect('?do=Main'); + } + + $action = Request::post('action'); + + if ($action === 'setstore') { + $this->setStore(); + } + } + + protected function doRender() + { + $action = Request::post('action'); + if ($action === 'setstore' && !Taskmanager::isFailed($this->mountTask)) { + Render::addTemplate('vmstore/mount', array( + 'task' => $this->mountTask['id'] + )); + return; + } + $vmstore = Property::getVmStoreConfig(); + if (isset($vmstore['storetype'])) { + $vmstore['pre-' . $vmstore['storetype']] = 'checked'; + } + $vmstore['token'] = Session::get('token'); + Render::addTemplate('page-vmstore', $vmstore); + } + + private function setStore() + { + foreach (array('storetype', 'nfsaddr', 'cifsaddr', 'cifsuser', 'cifspasswd') as $key) { + $vmstore[$key] = trim(Request::post($key, '')); + } + $storetype = $vmstore['storetype']; + if (!in_array($storetype, array('internal', 'nfs', 'cifs'))) { + Message::addError('value-invalid', 'type', $storetype); + Util::redirect('?do=VmStore'); + } + // Validate syntax of nfs/cifs + if ($storetype === 'nfs' && !preg_match('#^\S+:\S+$#is', $vmstore['nfsaddr'])) { + Message::addError('value-invalid', 'nfsaddr', $vmstore['nfsaddr']); + Util::redirect('?do=VmStore'); + } + $vmstore['cifsaddr'] = str_replace('\\', '/', $vmstore['cifsaddr']); + if ($storetype === 'cifs' && !preg_match('#^//\S+/.+$#is', $vmstore['cifsaddr'])) { + Message::addError('value-invalid', 'nfsaddr', $vmstore['nfsaddr']); + Util::redirect('?do=VmStore'); + } + if ($storetype === 'nfs') $addr = $vmstore['nfsaddr']; + if ($storetype === 'cifs') $addr = $vmstore['nfsaddr']; + if ($storetype === 'internal') $addr = 'none'; + $this->mountTask = Taskmanager::submit('MountVmStore', array( + 'address' => $addr, + 'type' => 'images', + 'username' => $vmstore['cifsuser'], + 'password' => $vmstore['cifspasswd'] + )); + Property::setVmStoreConfig($vmstore); + } + +}
\ No newline at end of file diff --git a/script/taskmanager.js b/script/taskmanager.js index fdbe4107..a34b3aa4 100644 --- a/script/taskmanager.js +++ b/script/taskmanager.js @@ -1,13 +1,16 @@ var tmItems = false; var tmErrors = 0; var TM_MAX_ERRORS = 5; +var tmIsRunning = false; function tmInit() { tmItems = $("div[data-tm-id]"); - if (tmItems.length === 0) return; + if (tmItems.length === 0) + return; tmItems.each(function(i, item) { item = $(item); + if (item.find('.data-tm-icon').length !== 0) return; if (item.is('[data-tm-progress]')) { item.append('<div class="data-tm-progress"><div class="progress"><div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%"></div></div></div>'); } @@ -16,7 +19,9 @@ function tmInit() } item.prepend('<span class="data-tm-icon" />'); }); - setTimeout(tmUpdate, 100); + if (!tmIsRunning) + setTimeout(tmUpdate, 50); + tmIsRunning = true; } function tmUpdate() @@ -25,19 +30,25 @@ function tmUpdate() tmItems.each(function(i, item) { item = $(item); var id = item.attr('data-tm-id'); - if (typeof id === 'undefined' || id === false || id === '') return; + if (typeof id === 'undefined' || id === false || id === '') + return; active.push(id); }); - if (active.length === 0) return; - $.post('api.php?do=taskmanager', { 'ids[]' : active, token : TOKEN }, function (data, status) { + if (active.length === 0) + return; + $.post('api.php?do=taskmanager', {'ids[]': active, token: TOKEN}, function(data, status) { // POST success - if (tmResult(data, status)) { + tmIsRunning = tmResult(data, status) + if (tmIsRunning) { setTimeout(tmUpdate, 1000); } - }, 'json').fail(function (jqXHR, textStatus, errorThrown) { + }, 'json').fail(function(jqXHR, textStatus, errorThrown) { // POST failure console.log("TaskManager Error: " + textStatus + " - " + errorThrown); - if (++tmErrors < TM_MAX_ERRORS) setTimeout(tmUpdate, 2000); + if (++tmErrors < TM_MAX_ERRORS) + setTimeout(tmUpdate, 2000); + else + tmIsRunning = false; }); } @@ -60,7 +71,8 @@ function tmResult(data, status) var counter = 0; for (var idx in data.tasks) { var task = data.tasks[idx]; - if (!task.id) continue; + if (!task.id) + continue; counter++; if (lastRunOnError) { task.statusCode = 'TASK_ERROR'; @@ -71,7 +83,8 @@ function tmResult(data, status) --tmErrors; } var obj = $('div[data-tm-id="' + task.id + '"]'); - if (!obj) continue; + if (!obj) + continue; if (task.statusCode !== 'TASK_WAITING' && task.statusCode !== 'TASK_PROCESSING') { obj.attr('data-tm-id', ''); } diff --git a/style/default.css b/style/default.css index 5e7dfeca..3e5f1a56 100644 --- a/style/default.css +++ b/style/default.css @@ -54,7 +54,8 @@ body { } .slx-ga { - min-width: 7em; + min-width: 8em; + text-align: left; } .slx-dialog { @@ -93,4 +94,8 @@ body { .slx-table td { padding-right: 5px; padding-bottom: 2px; +} + +.input-group { + margin-bottom: 2px; }
\ No newline at end of file diff --git a/templates/main-menu.html b/templates/main-menu.html index 8510bfec..24ee2238 100644 --- a/templates/main-menu.html +++ b/templates/main-menu.html @@ -23,6 +23,7 @@ <li class="divider"></li> <li class="dropdown-header">Server</li> <li><a href="?do=ServerSetup">Grundkonfiguration</a></li> + <li><a href="?do=VmStore">VM Speicherort</a></li> </ul> </li> </ul> diff --git a/templates/minilinux/download.html b/templates/minilinux/download.html new file mode 100644 index 00000000..2e32df5a --- /dev/null +++ b/templates/minilinux/download.html @@ -0,0 +1 @@ +<div data-tm-id="{{task}}" data-tm-log="error" data-tm-progress="progress">{{name}}</div>
\ No newline at end of file diff --git a/templates/minilinux/filelist.html b/templates/minilinux/filelist.html new file mode 100644 index 00000000..38b709f6 --- /dev/null +++ b/templates/minilinux/filelist.html @@ -0,0 +1,39 @@ +<div class="container"> + + {{#systems}} + <div class="panel panel-default"> + <div class="panel-heading"> + <h4>{{title}}</h4> + </div> + <div class="panel-body" id="download-{{id}}"> + <ul class="list-group"> + {{#files}} + <li class="list-group-item" id="{{uid}}"> + {{name}} + {{#changed}}<span class="btn btn-primary btn-sm" onclick="slxUpdate('{{uid}}', '{{id}}', '{{name}}')">Aktualisieren</span>{{/changed}} + </li> + {{/files}} + </ul> + </div> + </div> + {{/systems}} + {{^systems}} + <div class="row well well-sm">Keine Konfigurationspakete gefunden!</div> + {{/systems}} +</div> + +<script type="text/javascript"> +function slxUpdate(uid, id, name) +{ + $('#' + uid).load('?do=MiniLinux', + { action : "download", token : TOKEN, id : id, name : name }, + function(response, status, xhr) { + if (status === "error") { + var msg = "Fehler beim Abruf: "; + $('#' + uid).html(msg + xhr.status + " " + xhr.statusText); + } else { + setTimeout(tmInit, 50); + } + }); +} +</script>
\ No newline at end of file diff --git a/templates/page-main.html b/templates/page-main.html index af335a72..519d3abd 100644 --- a/templates/page-main.html +++ b/templates/page-main.html @@ -3,6 +3,12 @@ <p>Dies ist die bwLehrpool Konfigurationsoberfläche.</p> </div> <ul class="list-group"> +{{#vmstore}} + <li class="list-group-item list-group-item-info"> + Es ist noch kein Speicherort für die Virtuellen Maschinen festgelegt. + <a class="btn btn-sm btn-primary" href="?do=VmStore">Konfigurieren »</a> + </li> +{{/vmstore}} {{#ipxe}} <li class="list-group-item list-group-item-info"> Das Bootmenü ist veraltet oder wurde noch nicht generiert. diff --git a/templates/page-minilinux.html b/templates/page-minilinux.html index e742f82a..c1a4ebd6 100644 --- a/templates/page-minilinux.html +++ b/templates/page-minilinux.html @@ -1,24 +1,15 @@ -<div class="container"> - {{#files}} - <div class="panel panel-default"> - <div class="panel-heading"><h4> - » {{file}} - {{^progress}} - {{#update}} - Neue Version! <a class="btn btn-success" href="#" onclick="this.style.display='none';loadContent('#{{id}}', 'api.php?do=download&type=ml&file={{file}}&id={{id}}')">Download</a> - {{/update}} - {{^update}} - (Aktuell) - {{/update}} - {{/progress}} - </h4></div> - {{#progress}} - <script> setTimeout(function() { loadContent('#{{id}}', 'api.php?do=download&progress={{progress}}&id={{id}}&pid={{pid}}&file={{file}}'); }, 1000); // </script> - {{/progress}} - <div class="panel-body" id="{{id}}">{{description}}</div> - </div> - {{/files}} - {{^files}} - <div class="row well well-sm">Keine Konfigurationspakete gefunden!</div> - {{/files}} -</div> +<div class="container" id="systemlist"> + <div class="panel panel-default">Liste wird abgerufen...</div> + <script type="text/javascript"> + var slx_check = setInterval(function() { + if (typeof $ === 'undefined') return; + clearInterval(slx_check); + $('#systemlist').load('{{{listurl}}}', function( response, status, xhr ) { + if ( status === "error" ) { + var msg = "Fehler beim Abruf: "; + $( "#systemlist" ).html( msg + xhr.status + " " + xhr.statusText ); + } + }) + }, 100); + </script> +</div>
\ No newline at end of file diff --git a/templates/page-vmstore.html b/templates/page-vmstore.html new file mode 100644 index 00000000..8732276f --- /dev/null +++ b/templates/page-vmstore.html @@ -0,0 +1,89 @@ +<div class="container"> + <form role="form" method="post" action="?do=VmStore"> + <input type="hidden" name="token" value="{{token}}"> + <input type="hidden" name="action" value="setstore"> + <div class="panel panel-default"> + <div class="panel-heading"> + VM Speicherort <a class="btn btn-default" data-toggle="modal" data-target="#help-store"><span class="glyphicon glyphicon-question-sign"></span></a> + </div> + <div class="panel-body"> + <p>Bitte wählen Sie, wo die Images der Virtuellen Maschinen gespeichert werden sollen.</p> + <div class="panel panel-default"> + <div class="panel-heading"> + <input type="radio" name="storetype" value="internal" {{pre-internal}}> Intern + </div> + <div class="panel-body"> + Keine Weitere Konfiguration notwendig + </div> + </div> + <div class="panel panel-default"> + <div class="panel-heading"> + <input type="radio" name="storetype" value="nfs" {{pre-nfs}}> NFS + </div> + <div class="panel-body"> + <div class="input-group"> + <span class="input-group-addon slx-ga"> + NFS-Export + </span> + <input type="text" class="form-control" name="nfsaddr" value="{{nfsaddr}}" placeholder="1.2.3.4:/export/bwlp"> + </div> + </div> + </div> + <div class="panel panel-default"> + <div class="panel-heading"> + <input type="radio" name="storetype" value="cifs" {{pre-cifs}}> CIFS + </div> + <div class="panel-body"> + <div class="input-group"> + <span class="input-group-addon slx-ga"> + UNC-Pfad + </span> + <input type="text" class="form-control" name="cifsaddr" value="{{cifsaddr}}" placeholder="\\samba.server.example.com\bwlp"> + </div> + <div class="input-group"> + <span class="input-group-addon slx-ga"> + Benutzername + </span> + <input type="text" class="form-control" name="cifsuser" value="{{cifsuser}}" placeholder="Benutzername"> + </div> + <div class="input-group"> + <span class="input-group-addon slx-ga"> + Passwort + </span> + <input type="text" class="form-control" name="cifspasswd" value="{{cifspasswd}}" placeholder="Passwort"> + </div> + </div> + </div> + <button class="btn btn-primary" type="submit">Speichern</button> + </div> + </div> + </form> +</div> + +<div class="modal fade" id="help-store" tabindex="-1" role="dialog"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header">VM Speicherort</div> + <div class="modal-body"> + <p> + Für Testzwecke können die VMs direkt auf dem Satellitenserver gespeichert werden. Sofern Sie + jedoch die ausgelieferte Satelliten-vmdk betreiben bedenken Sie bitte, dass Sie dann nur ca. 100GB + Speicher zur Verfügung haben. + </p> + <p> + Im Produktivbetrieb bietet es sich an, hierfür einen performanten Netzwerkspeicher zu benutzen. + Dieser Netzwerkspeicher kann per NFS oder CIFS/SMB eingebunden werden. In jedem Fall muss sichergestellt + werden, dass der Satellitenserver zum Hinzufügen neuer Virtueller Maschinen Schreibzugriff auf + diesen Netzwerkspeicher hat. Bei der Nutzung von NFSv3 kann dies IP-Basiert eingerichtet werden, + für die Nutzung von CIFS/SMB können Sie Zugangsdaten angaben, die zum Schreiben berechtigen. + </p> + <p> + Die bwLehrpool-Clients brauchen lediglich Lesezugriff auf den Netzwerkspeicher (und sollten aus + Sicherheitsgründen auch wirklich nur lesen können). Bei CIFS/SMB erreichen Sie dies am einfachsten, + indem Sie passwortlosen Gastzugriff mit Leserechten auf die Freigabe erlauben. + </p> + </div> + <div class="modal-footer"><a class="btn btn-primary" data-dismiss="modal">Schließen</a></div> + </div> + </div> +</div> diff --git a/templates/vmstore/mount.html b/templates/vmstore/mount.html new file mode 100644 index 00000000..d781d061 --- /dev/null +++ b/templates/vmstore/mount.html @@ -0,0 +1,28 @@ +<div class="container"> + + <div class="panel panel-default"> + <div class="panel-heading"> + VM Speicherort wird konfiguriert + </div> + + <div class="panel-body"> + <div data-tm-id="{{task}}" data-tm-log="messages" data-tm-callback="mountCb">Konfigurieren</div> + + <br> + <div id="finish" class="pull-right" style="display:none"> + <a href="?do=VmStore" class="btn btn-primary">Zurück</a> + </div> + <script type="text/javascript"> + function mountCb(task) + { + if (!task || !task.statusCode) + return; + if (task.statusCode !== 'TASK_WAITING' && task.statusCode !== 'TASK_PROCESSING') { + $('#finish').attr('style', ''); + } + } + </script> + + </div> + </div> +</div>
\ No newline at end of file |