From a4f4147b6fe5f2a003a61cf8a8f7508c94130b31 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Mon, 26 May 2014 22:49:54 +0200 Subject: WIP --- api.php | 16 ++++--- apis/getconfig.inc.php | 17 ++++++++ apis/init.inc.php | 7 +++ apis/taskmanager.inc.php | 10 +++-- config.php | 3 +- inc/property.inc.php | 47 +++++++++++++++++++++ inc/render.inc.php | 1 - inc/taskmanager.inc.php | 41 ++++++++++++------ inc/trigger.inc.php | 40 +++++++++++++++++- index.php | 2 + modules/main.inc.php | 9 +++- modules/minilinux.inc.php | 73 ++++++++++++++++++++++++++++---- modules/sysconfig.inc.php | 1 + modules/vmstore.inc.php | 72 +++++++++++++++++++++++++++++++ script/taskmanager.js | 33 ++++++++++----- style/default.css | 7 ++- templates/main-menu.html | 1 + templates/minilinux/download.html | 1 + templates/minilinux/filelist.html | 39 +++++++++++++++++ templates/page-main.html | 6 +++ templates/page-minilinux.html | 39 +++++++---------- templates/page-vmstore.html | 89 +++++++++++++++++++++++++++++++++++++++ templates/vmstore/mount.html | 28 ++++++++++++ 23 files changed, 511 insertions(+), 71 deletions(-) create mode 100644 apis/init.inc.php create mode 100644 modules/vmstore.inc.php create mode 100644 templates/minilinux/download.html create mode 100644 templates/minilinux/filelist.html create mode 100644 templates/page-vmstore.html create mode 100644 templates/vmstore/mount.html diff --git a/api.php b/api.php index 16408440..f8e9c4d5 100644 --- a/api.php +++ b/api.php @@ -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 .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 @@ 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 @@ + 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 - ', 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 +} diff --git a/index.php b/index.php index ae03e86c..31a7bcc7 100644 --- a/index.php +++ b/index.php @@ -1,5 +1,7 @@ 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 @@ +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('
'); } @@ -16,7 +19,9 @@ function tmInit() } item.prepend(''); }); - 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 @@
  • Grundkonfiguration
  • +
  • VM Speicherort
  • 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 @@ +
    {{name}}
    \ 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 @@ +
    + + {{#systems}} +
    +
    +

    {{title}}

    +
    +
    +
      + {{#files}} +
    • + {{name}} + {{#changed}}Aktualisieren{{/changed}} +
    • + {{/files}} +
    +
    +
    + {{/systems}} + {{^systems}} +
    Keine Konfigurationspakete gefunden!
    + {{/systems}} +
    + + \ 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 @@

    Dies ist die bwLehrpool Konfigurationsoberfläche.