summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DB_SCRIBBLE7
-rw-r--r--apis/download.inc.php96
-rw-r--r--apis/exec.inc.php75
-rw-r--r--apis/getconfig.inc.php1
-rw-r--r--config.php13
-rwxr-xr-xexternal/build_ipxe.sh40
-rw-r--r--external/tgz/list.php (renamed from fakeremote/list.php)0
-rw-r--r--inc/message.inc.php3
-rw-r--r--inc/session.inc.php2
-rw-r--r--modules/adduser.inc.php16
-rw-r--r--modules/ipxe.inc.php35
-rw-r--r--modules/main.inc.php14
-rw-r--r--modules/minilinux.inc.php86
-rw-r--r--modules/sysconfig.inc.php29
-rw-r--r--templates/download-error.html2
-rw-r--r--templates/download-progress.html6
-rw-r--r--templates/exec-error.html1
-rw-r--r--templates/exec-progress.html4
-rw-r--r--templates/main-menu.html7
-rw-r--r--templates/page-ipxe.html17
-rw-r--r--templates/page-main.html9
-rw-r--r--templates/page-minilinux.html24
-rw-r--r--templates/page-tgz-list.html2
-rw-r--r--templates/txt-ipxeconfig.html7
-rw-r--r--templates/txt-pxeconfig.html68
25 files changed, 524 insertions, 40 deletions
diff --git a/DB_SCRIBBLE b/DB_SCRIBBLE
index d4ce72a2..34bfdb00 100644
--- a/DB_SCRIBBLE
+++ b/DB_SCRIBBLE
@@ -50,12 +50,12 @@ INSERT INTO `setting` (`setting`, `defaultvalue`, `permissions`, `validator`, `d
('SLX_PROXY_PORT', '', 2, 'regex:/^\\d*$/', 'Der Port des zu verwendenden Proxy Servers.'),
('SLX_PROXY_TYPE', 'socks5', 2, '', 'Art des Proxys.\r\n*socks4*, *socks5*,\r\n*http-connect* (HTTP Proxy mit Unterstützung der CONNECT-Methode),\r\n*http-relay* (Klassischer HTTP Proxy)'),
('SLX_ROOT_PASS', '', 2, 'function:linuxPassword', 'Das root-Passwort des Grundsystems. Wird nur für Diagnosezwecke am Client benötigt.\r\nFeld leer lassen, um root-Logins zu verbieten.\r\n/Hinweis/: Das Passwort wird crypt $6$ gehasht, daher wir das Passwort nach dem Speichern nicht mehr lesbar sein!'),
-('SLX_VM_NFS', '', 2, '', 'Serveradresse und mount point des NFS Servers, auf dem die virtuellen Maschinen liegen.\r\nBeispiel: *vm-store.example.com:/data/images*');
+('SLX_VM_NFS', '(SERVER):/srv/openslx/nfs', 2, '', 'Serveradresse und mount point des NFS Servers, auf dem die virtuellen Maschinen liegen. Um den integrierten NFS-Server zu nutzen, muss die Angabe *<IP_DIESES_SERVERS>:/srv/openslx/mnt* lauten.\r\nAnsonsten lässt sich ein beliebiger NFS-Server angeben. Beispiel: *vm-store.example.com:/data/images*');
-CRREATE TABLE IF NOT EXISTS `setting_distro` (
+CREATE TABLE IF NOT EXISTS `setting_distro` (
`distroid` int(10) unsigned NOT NULL,
`setting` varchar(28) NOT NULL,
`value` text NOT NULL,
@@ -77,7 +77,8 @@ CREATE TABLE IF NOT EXISTS `user` (
`phone` varchar(100) DEFAULT NULL,
`email` varchar(100) DEFAULT NULL,
`permissions` int(10) unsigned NOT NULL,
- PRIMARY KEY (`userid`)
+ PRIMARY KEY (`userid`),
+ UNIQUE KEY `login` (`login`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
diff --git a/apis/download.inc.php b/apis/download.inc.php
index 4be67521..b9033c6f 100644
--- a/apis/download.inc.php
+++ b/apis/download.inc.php
@@ -3,38 +3,106 @@
User::load();
if (!User::hasPermission('superadmin')) die('No permission');
-if (!isset($_REQUEST['type'])) die('No type');
-if (!isset($_REQUEST['file'])) die('No file');
-if (!isset($_REQUEST['id'])) die('No id');
require_once('inc/render.inc.php');
-$type = $_REQUEST['type'];
+if (!isset($_REQUEST['file'])) die('No file');
+if (!isset($_REQUEST['id'])) die('No id');
$file = preg_replace('/[^a-z0-9\.\-_]/is', '', $_REQUEST['file']);
$id = $_REQUEST['id'];
+// Progress update only
+
+if (isset($_REQUEST['progress'])) {
+ $progress = preg_replace('/[^a-z0-9\-]/', '', $_REQUEST['progress']);
+ $pid = (isset($_REQUEST['pid']) ? (int)$_REQUEST['pid'] : 0);
+ $log = '/tmp/' . $progress . '.log';
+ if (!file_exists($log)) {
+ echo Render::parse('download-error', array('file' => $file));
+ exit(0);
+ }
+ $error = false;
+ $percent = 0;
+ $fh = fopen($log, 'r');
+ while (!feof($fh)) {
+ $line = fgets($fh);
+ if (preg_match('/ ERROR (\d{3}):/', $line, $out)) {
+ $error = $out[1];
+ break;
+ }
+ if (preg_match('/ (\d+)% /', $line, $out)) {
+ $percent = $out[1];
+ }
+ }
+ fclose($fh);
+ if ($error === false && $pid > 0 && $percent != 100 && !posix_kill($pid, 0)) $error = 'Process died - ' . $line;
+ if ($error !== false) {
+ echo Render::parse('download-error', array('file' => $file, 'code' => $error));
+ unlink($log);
+ exit(0);
+ }
+ if ($percent == 100) {
+ echo Render::parse('download-complete' ,array('file' => $file));
+ unlink($log);
+ } else {
+ echo Render::parse('download-progress' ,array('file' => $file, 'progress' => $progress, 'id' => $id, 'percent' => $percent, 'pid' => $pid));
+ }
+ exit(0);
+}
+
+// Actual download request
+
+if (!isset($_REQUEST['type'])) die('No type');
+
+
+$type = $_REQUEST['type'];
+$directExec = true;
+$overwrite = isset($_REQUEST['exec']);
+
switch ($type) {
case 'tgz':
$remote = CONFIG_REMOTE_TGZ;
$local = CONFIG_TGZ_LIST_DIR;
break;
+case 'ml':
+ $remote = CONFIG_REMOTE_ML;
+ $local = CONFIG_HTTP_DIR . '/default';
+ $directExec = false;
+ $overwrite = true;
+ break;
default:
die('Invalid download type');
}
@mkdir($local, 0755, true);
-if (file_exists($local . '/' . $file) && !isset($_REQUEST['exec'])) {
- echo Render::parse('download-overwrite', array('file' => $file, 'id' => $id, 'query' => $_SERVER['REQUEST_URI']));;
+if (file_exists($local . '/' . $file) && !$overwrite) {
+ echo Render::parse('download-overwrite', array('file' => $file, 'id' => $id, 'query' => $_SERVER['REQUEST_URI']));
exit(0);
}
-$ret = Util::downloadToFile($local . '/' . $file, $remote . '/' . $file, 20, $code);
-if ($ret === false || $code < 200 || $code >= 300) {
- @unlink($local . '/' . $file);
- echo Render::parse('download-error', array('file' => $file, 'remote' => $remote, 'code' => $code));
- exit(0);
+if ($directExec) {
+ // Blocking inline download
+ $ret = Util::downloadToFile($local . '/' . $file, $remote . '/' . $file, 20, $code);
+ if ($ret === false || $code < 200 || $code >= 300) {
+ @unlink($local . '/' . $file);
+ echo Render::parse('download-error', array('file' => $file, 'remote' => $remote, 'code' => $code));
+ exit(0);
+ }
+
+ // No execution - just return dialog
+ echo Render::parse('download-complete', array('file' => $file));
+} else {
+ // Use WGET
+ $logfile = 'slx-' . mt_rand() . '-' . time();
+ exec("wget --timeout=10 -O $local/$file -o /tmp/${logfile}.log -b $remote/$file", $retstr, $retval);
+ unlink("$local/${file}.md5");
+ if ($retval != 0) {
+ echo Render::parse('download-error', array('file' => $destination, 'remote' => $source, 'code' => implode(' // ', $retstr) . ' - ' . $retval));
+ exit(0);
+ }
+ $pid = 0;
+ foreach ($retstr as $line) if (preg_match('/ (\d+)([,\.\!\:]|$)/', $line, $out)) $pid = $out[1];
+ file_put_contents("$local/${file}.lck", $pid . ' ' . $logfile);
+ echo Render::parse('download-progress', array('file' => $file, 'progress' => $logfile, 'id' => $id, 'percent' => '0', 'pid' => $pid));
}
-// No execution - just return dialog
-echo Render::parse('download-complete', array('file' => $file));
-
diff --git a/apis/exec.inc.php b/apis/exec.inc.php
new file mode 100644
index 00000000..94a94a00
--- /dev/null
+++ b/apis/exec.inc.php
@@ -0,0 +1,75 @@
+<?php
+
+User::load();
+
+if (!User::hasPermission('superadmin')) die('No permission');
+
+require_once('inc/render.inc.php');
+
+error_log('**URI: '. $_SERVER['REQUEST_URI']);
+
+if (!isset($_REQUEST['id'])) die('No id');
+$id = $_REQUEST['id'];
+
+// Progress update only
+
+if (isset($_REQUEST['progress'])) {
+ $progress = preg_replace('/[^a-z0-9\-]/', '', $_REQUEST['progress']);
+ $pid = (isset($_REQUEST['pid']) ? (int)$_REQUEST['pid'] : 0);
+ $log = '/tmp/' . $progress . '.log';
+ if (!file_exists($log)) {
+ echo Render::parse('exec-error');
+ exit(0);
+ }
+ $lastLines = array();
+ $fh = fopen($log, 'r');
+ while (!feof($fh)) {
+ $line = fgets($fh);
+ $lastLines[] = $line;
+ if (count($lastLines) > 10) array_shift($lastLines);
+ }
+ fclose($fh);
+ $running = ($pid == 0 || posix_kill($pid, 0));
+ echo Render::parse('exec-progress', array('progress' => $progress, 'id' => $id, 'pid' => $pid, 'running' => $running, 'text' => implode('', $lastLines)));
+ if (!$running) unlink($log);
+ exit(0);
+}
+
+// Actual download request
+// type ip id
+
+if (!isset($_REQUEST['type'])) die('No type');
+
+
+$type = $_REQUEST['type'];
+
+switch ($type) {
+case 'ipxe':
+ if (!isset($_REQUEST['ip'])) die('No IP given');
+ $ip = preg_replace('/[^0-9\.]/', '', $_REQUEST['ip']);
+ $command = '/opt/openslx/build_ipxe.sh "' . CONFIG_IPXE_DIR . '/last-ip" "' . $ip . '"';
+ $conf = Render::parse('txt-ipxeconfig', array(
+ 'SERVER' => $ip
+ ));
+ if (false === file_put_contents('/opt/openslx/ipxe/ipxelinux.ipxe', $conf)) die('Error writing iPXE Config');
+ $conf = Render::parse('txt-pxeconfig', array(
+ 'SERVER' => $ip,
+ 'DEFAULT' => 'openslx'
+ ));
+ if (false === file_put_contents(CONFIG_TFTP_DIR . '/pxelinux.cfg/default', $conf)) die('Error writing PXE Menu');
+ break;
+default:
+ die('Invalid exec type');
+}
+
+$logfile = 'slx-' . mt_rand() . '-' . time();
+error_log('**EXEC: ' . "$command '/tmp/${logfile}.log'");
+exec("$command '/tmp/${logfile}.log'", $retstr, $retval);
+if ($retval != 0) {
+ echo Render::parse('exec-error', array('error' => implode(' // ', $retstr) . ' - ' . $retval));
+ exit(0);
+}
+$pid = 0;
+foreach ($retstr as $line) if (preg_match('/PID: (\d+)\./', $line, $out)) $pid = $out[1];
+echo Render::parse('exec-progress', array('progress' => $logfile, 'id' => $id, 'pid' => $pid, 'running' => true));
+
diff --git a/apis/getconfig.inc.php b/apis/getconfig.inc.php
index a3d2bd91..6edb55be 100644
--- a/apis/getconfig.inc.php
+++ b/apis/getconfig.inc.php
@@ -5,5 +5,6 @@ $res = Database::simpleQuery('SELECT setting.setting, setting.defaultvalue, sett
LEFT JOIN setting_global AS tbl USING (setting)
ORDER BY setting ASC'); // TODO: Add setting groups and sort order
while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ if (empty($row['value'])) $row['value'] = $row['defaultvalue'];
echo $row['setting'] . "='" . str_replace("'", "'\"'\"'", $row['value']) . "'\n";
}
diff --git a/config.php b/config.php
index 5b44d1cf..ac6a9de4 100644
--- a/config.php
+++ b/config.php
@@ -4,7 +4,7 @@
define('CONFIG_DEBUG', true);
define('CONFIG_SESSION_DIR', '/tmp/openslx');
-define('CONFIG_SESSION_TIMEOUT', 86400);
+define('CONFIG_SESSION_TIMEOUT', 86400 * 3);
//define('CONFIG_SQL_BACKEND', 'mysql');
//define('CONFIG_SQL_HOST', 'localhost');
@@ -13,8 +13,13 @@ define('CONFIG_SQL_USER', 'openslx');
define('CONFIG_SQL_PASS', 'geheim');
//define('CONFIG_SQL_DB', 'openslx');
-define('CONFIG_TGZ_LIST_DIR', '/tmp/configs');
-define('CONFIG_HTTP_DIR', '/tmp/active-config');
+define('CONFIG_TGZ_LIST_DIR', '/opt/openslx/configs');
-define('CONFIG_REMOTE_TGZ', 'http://127.0.0.1/fakeremote');
+define('CONFIG_REMOTE_TGZ', 'http://mltk.boot.openslx.org/tgz');
+define('CONFIG_REMOTE_ML', 'http://mltk.boot.openslx.org/update');
+
+define('CONFIG_TFTP_DIR', '/srv/openslx/tftp');
+define('CONFIG_HTTP_DIR', '/srv/openslx/www/boot');
+
+define('CONFIG_IPXE_DIR', '/opt/openslx/ipxe');
diff --git a/external/build_ipxe.sh b/external/build_ipxe.sh
new file mode 100755
index 00000000..8cb23cd0
--- /dev/null
+++ b/external/build_ipxe.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+# Call: $0 <ip_file> <server_ip> <logfile>
+# Self-Call: $0 --exec <ip_file> <server_ip>
+
+if [ $# -lt 3 ]; then
+ echo "Falscher Aufruf: Keine zwei Parameter angegeben!"
+ exit 1
+fi
+
+if [ "$1" != "--exec" ]; then
+ $0 --exec "$1" "$2" > "$3" 2>&1 &
+ RET=$!
+ echo "PID: ${RET}."
+ exit 0
+fi
+
+FILE="$2"
+SERVER="$3"
+
+cd "/opt/openslx/ipxe/src"
+
+[ -e "bin/undionly.kkkpxe" ] && unlink "bin/undionly.kkkpxe"
+
+make bin/undionly.kkkpxe EMBED=../ipxelinux.ipxe,../pxelinux.0
+
+if [ ! -e "bin/undionly.kkkpxe" -o "$(stat -c %s "bin/undionly.kkkpxe")" -lt 80000 ]; then
+ echo "Error compiling ipxelinux.0"
+ exit 1
+fi
+
+if ! cp "bin/undionly.kkkpxe" "/srv/openslx/tftp/ipxelinux.0"; then
+ echo "** Error copying ipxelinux.0 to target **"
+ exit 1
+fi
+
+echo -n "$SERVER" > "$FILE"
+echo " ** SUCCESS **"
+exit 0
+
diff --git a/fakeremote/list.php b/external/tgz/list.php
index 5c8d1c67..5c8d1c67 100644
--- a/fakeremote/list.php
+++ b/external/tgz/list.php
diff --git a/inc/message.inc.php b/inc/message.inc.php
index d39f0f9b..ea6cd20d 100644
--- a/inc/message.inc.php
+++ b/inc/message.inc.php
@@ -16,8 +16,11 @@ $error_text = array(
'remote-timeout' => 'Konnte Ressource {{0}} nicht herunterladen',
'remote-parse-failed' => 'Parsen der empfangenen Daten fehlgeschlagen ({{0}})',
'missing-file' => 'Es wurde keine Datei ausgewählt!',
+ 'invalid-file' => 'Die Datei {{0}} existiert nicht!',
'upload-complete' => 'Upload von {{0}} war erfolgreich',
'upload-failed' => 'Upload von {{0}} schlug fehl!',
+ 'config-activated' => 'Konfiguration wurde aktiviert',
+ 'error-write' => 'Fehler beim Schreiben von {{0}}',
);
class Message
diff --git a/inc/session.inc.php b/inc/session.inc.php
index 402e6cd9..3ba614f2 100644
--- a/inc/session.inc.php
+++ b/inc/session.inc.php
@@ -2,7 +2,7 @@
require_once('config.php');
-@mkdir(CONFIG_SESSION_DIR, 0700);
+@mkdir(CONFIG_SESSION_DIR, 0700, true);
@chmod(CONFIG_SESSION_DIR, 0700);
if (!is_writable(CONFIG_SESSION_DIR)) die('Config error: Session Path not writable!');
diff --git a/modules/adduser.inc.php b/modules/adduser.inc.php
index 04b6044f..f152643b 100644
--- a/modules/adduser.inc.php
+++ b/modules/adduser.inc.php
@@ -10,6 +10,9 @@ if (isset($_POST['action']) && $_POST['action'] === 'adduser') {
} elseif ($_POST['pass1'] !== $_POST['pass2']) {
Message::addError('password-mismatch');
Util::redirect('?do=adduser');
+ } elseif (Database::queryFirst('SELECT userid FROM user LIMIT 1') !== false) {
+ Message::addError('adduser-disabled');
+ Util::redirect('?do=session&action=login');
} else {
$data = array(
'user' => $_POST['user'],
@@ -22,17 +25,18 @@ if (isset($_POST['action']) && $_POST['action'] === 'adduser') {
if (Database::exec('INSERT INTO user SET login = :user, passwd = :pass, fullname = :fullname, phone = :phone, email = :email', $data) != 1) {
Util::traceError('Could not create new user in DB');
}
- $adduser_success = true;
+ // Make it superadmin if first user. This method sucks as it's a race condition but hey...
+ $ret = Database::queryFirst('SELECT Count(*) AS num FROM user');
+ if ($ret !== false && $ret['num'] == 1) {
+ Database::exec('UPDATE user SET permissions = 1');
+ }
+ Message::addInfo('adduser-success');
+ Util::redirect('?do=session&action=login');
}
}
function render_module()
{
- // A user was added. Show success message and bail out
- if (isset($adduser_success)) {
- Message::addInfo('adduser-success');
- return;
- }
// No user was added, check if current user is allowed to add a new user
// Currently you can only add users if there is no user yet. :)
if (Database::queryFirst('SELECT userid FROM user LIMIT 1') !== false) {
diff --git a/modules/ipxe.inc.php b/modules/ipxe.inc.php
new file mode 100644
index 00000000..869f4c72
--- /dev/null
+++ b/modules/ipxe.inc.php
@@ -0,0 +1,35 @@
+<?php
+
+User::load();
+
+if (!User::hasPermission('superadmin')) {
+ Message::addError('no-permission');
+ Util::redirect('?do=main');
+}
+
+if (isset($_POST['action'])) {
+ if ($_POST['action'] === 'compile') {
+ if (!Util::verifyToken()) {
+ Util::redirect('?do=main');
+ }
+ }
+}
+
+function render_module()
+{
+ $ips = array();
+ $current = CONFIG_IPXE_DIR . '/last-ip';
+ if (file_exists($current)) $current = file_get_contents($current);
+ exec('/bin/ip a', $retval);
+ foreach ($retval as $ip) {
+ if (preg_match('#inet (\d+\.\d+\.\d+\.\d+)/\d+.*scope#', $ip, $out) && $out[1] !== '127.0.0.1') {
+ $ips[] = array(
+ 'ip' => $out[1],
+ 'current' => ($out[1] == $current)
+ );
+ }
+ }
+ Render::addTemplate('page-ipxe', array('ips' => $ips, 'token' => Session::get('token')));
+}
+
+
diff --git a/modules/main.inc.php b/modules/main.inc.php
index 007fb296..31aef55e 100644
--- a/modules/main.inc.php
+++ b/modules/main.inc.php
@@ -6,14 +6,20 @@ function render_module()
{
// Render::setTitle('abc');
- Render::openTag('h1', array('class' => 'wurst kacke'));
- Render::closeTag('h1');
-
if (!User::isLoggedIn()) {
Render::addTemplate('page-main-guest');
return;
}
// Logged in here
- Render::addTemplate('page-main', array('user' => User::getName()));
+ $ipxe = true;
+ $file = CONFIG_IPXE_DIR . '/last-ip';
+ if (file_exists($file)) {
+ $last = file_get_contents($file);
+ exec('/bin/ip a', $ips);
+ foreach ($ips as $ip) {
+ if (preg_match("#inet $last/\d+.*scope#", $ip)) $ipxe = false;
+ }
+ }
+ Render::addTemplate('page-main', array('user' => User::getName(), 'ipxe' => $ipxe));
}
diff --git a/modules/minilinux.inc.php b/modules/minilinux.inc.php
new file mode 100644
index 00000000..3508fb43
--- /dev/null
+++ b/modules/minilinux.inc.php
@@ -0,0 +1,86 @@
+<?php
+
+User::load();
+
+if (!User::hasPermission('superadmin')) {
+ Message::addError('no-permission');
+ Util::redirect('?do=main');
+}
+
+function render_module()
+{
+ $files = array();
+ checkFile($files, 'kernel');
+ checkFile($files, 'initramfs-stage31');
+ checkFile($files, 'stage32.sqfs');
+ checkFile($files, 'vmware.sqfs');
+ Render::addTemplate('page-minilinux', array('files' => $files, 'token' => Session::get('token')));
+}
+
+function checkFile(&$files, $name)
+{
+ static $someId = 0;
+ $remote = CONFIG_REMOTE_ML . "/${name}.md5";
+ $localTarget = CONFIG_HTTP_DIR . "/default/${name}";
+ $local = "${localTarget}.md5";
+ $localLock = "${localTarget}.lck";
+
+ // Maybe already in progress?
+ if (file_exists($localLock)) {
+ $data = explode(' ', file_get_contents($localLock));
+ if (count($data) == 2) {
+ $pid = (int)$data[0];
+ if (posix_kill($pid, 0)) {
+ $files[] = array(
+ 'file' => $name,
+ 'id' => 'id' . $someId++,
+ 'pid' => $pid,
+ 'progress' => $data[1]
+ );
+ return true;
+ } else {
+ unlink($localLock);
+ }
+ } else {
+ unlink($localLock);
+ }
+ }
+
+ // Not in progress, normal display
+ if (!file_exists($local) || filemtime($local) + 300 < time()) {
+ if (file_exists($localTarget)) {
+ $existingMd5 = md5_file($localTarget);
+ } else {
+ $existingMd5 = '<missing>';
+ }
+ if (file_put_contents($local, $existingMd5) === false) {
+ @unlink($local);
+ Message::addWarning('error-write', $local);
+ }
+ } else {
+ $existingMd5 = file_get_contents($local);
+ }
+ $existingMd5 = strtolower(preg_replace('/[^0-9a-f]/is', '', $existingMd5));
+ $remoteMd5 = Util::download($remote, 3, $code);
+ $remoteMd5 = strtolower(preg_replace('/[^0-9a-f]/is', '', $existingMd5));
+ if ($code != 200) {
+ Message::addError('remote-timeout', $remote);
+ return false;
+ }
+ if ($existingMd5 === $remoteMd5) {
+ // Up to date
+ $files[] = array(
+ 'file' => $name,
+ 'id' => 'id' . $someId++,
+ );
+ return true;
+ }
+ // New version on server
+ $files[] = array(
+ 'file' => $name,
+ 'id' => 'id' . $someId++,
+ 'update' => true
+ );
+ return true;
+}
+
diff --git a/modules/sysconfig.inc.php b/modules/sysconfig.inc.php
index d5300194..f10446ed 100644
--- a/modules/sysconfig.inc.php
+++ b/modules/sysconfig.inc.php
@@ -27,6 +27,33 @@ if (isset($_POST['action']) && $_POST['action'] === 'upload') {
Util::redirect('?do=sysconfig');
}
+if (isset($_REQUEST['action']) && $_REQUEST['action'] === 'activate') {
+ if (!Util::verifyToken()) {
+ Util::redirect('?do=sysconfig');
+ }
+ if (!User::hasPermission('superadmin')) {
+ Message::addError('no-permission');
+ Util::redirect('?do=sysconfig');
+ }
+ if (!isset($_REQUEST['file'])) {
+ Message::addError('missing-file');
+ Util::redirect('?do=sysconfig');
+ }
+ $file = preg_replace('/[^a-z0-9\-_\.]/', '', $_REQUEST['file']);
+ $path = CONFIG_TGZ_LIST_DIR . '/' . $file;
+ if (!file_exists($path)) {
+ Message::addError('invalid-file', $file);
+ Util::redirect('?do=sysconfig');
+ }
+ mkdir(CONFIG_HTTP_DIR . '/default', 0755, true);
+ $linkname = CONFIG_HTTP_DIR . '/default/config.tgz';
+ @unlink($linkname);
+ if (file_exists($linkname)) Util::traceError('Could not delete old config.tgz link!');
+ if (!symlink($path, $linkname)) Util::traceError("Could not symlink to $path at $linkname!");
+ Message::addSuccess('config-activated');
+ Util::redirect('?do=sysconfig');
+}
+
function render_module()
{
if (!isset($_REQUEST['action'])) $_REQUEST['action'] = 'list';
@@ -52,7 +79,7 @@ function list_configs()
$files = array();
foreach (glob(CONFIG_TGZ_LIST_DIR . '/*.tgz') as $file) {
$files[] = array(
- 'file' => $file
+ 'file' => basename($file)
);
}
Render::addTemplate('page-tgz-list', array('files' => $files, 'token' => Session::get('token')));
diff --git a/templates/download-error.html b/templates/download-error.html
index ca40acee..70826234 100644
--- a/templates/download-error.html
+++ b/templates/download-error.html
@@ -1 +1 @@
-<div class="alert alert-danger">Downloading {{file}} from {{remote}} failed! ({{code}})</div>
+<div class="alert alert-danger">Downloading {{file}} {{#remote}} from {{remote}} {{/remote}} failed! ({{code}})</div>
diff --git a/templates/download-progress.html b/templates/download-progress.html
new file mode 100644
index 00000000..81b31901
--- /dev/null
+++ b/templates/download-progress.html
@@ -0,0 +1,6 @@
+<div class="progress progress-striped active">
+ <div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="{{percent}}" aria-valuemin="0" aria-valuemax="100" style="width: {{percent}}%">
+ <span class="sr-only">{{percent}}% Complete</span>
+ </div>
+ <script> setTimeout(function() { $('#{{id}}').load('api.php?do=download&progress={{progress}}&file={{file}}&id={{id}}&pid={{pid}}'); }, 2000); // </script>
+</div>
diff --git a/templates/exec-error.html b/templates/exec-error.html
new file mode 100644
index 00000000..0a82e1df
--- /dev/null
+++ b/templates/exec-error.html
@@ -0,0 +1 @@
+<div class="alert alert-danger"><p>Ausführung fehlgeschlagen!</p>{{error}}</div>
diff --git a/templates/exec-progress.html b/templates/exec-progress.html
new file mode 100644
index 00000000..0583a74a
--- /dev/null
+++ b/templates/exec-progress.html
@@ -0,0 +1,4 @@
+<div class="well well-sm">
+ <pre>{{text}}</pre>
+ {{#running}}<script> setTimeout(function() { $('#{{id}}').load('api.php?do=exec&progress={{progress}}&id={{id}}&pid={{pid}}'); }, 2000); // </script>{{/running}}
+</div>
diff --git a/templates/main-menu.html b/templates/main-menu.html
index 021daf6d..799d92be 100644
--- a/templates/main-menu.html
+++ b/templates/main-menu.html
@@ -7,7 +7,7 @@
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
- <a class="navbar-brand" href="#">OpenSLX Admin</a>
+ <a class="navbar-brand" href="?do=main">OpenSLX Admin</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
@@ -16,8 +16,9 @@
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Einstellungen<b class="caret"></b></a>
<ul class="dropdown-menu">
- <li><a href="?do=baseconfig">Basis</a></li>
- <li><a href="?do=sysconfig">System</a></li>
+ <li><a href="?do=minilinux">MiniLinux</a></li>
+ <li><a href="?do=baseconfig">KonfigurationsVariablen</a></li>
+ <li><a href="?do=sysconfig">SystemKonfiguration</a></li>
<li><a href="?do=printconfig">Drucken</a></li>
<li class="divider"></li>
<li class="dropdown-header">Nav header</li>
diff --git a/templates/page-ipxe.html b/templates/page-ipxe.html
new file mode 100644
index 00000000..7910c5af
--- /dev/null
+++ b/templates/page-ipxe.html
@@ -0,0 +1,17 @@
+<div class="container">
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ Bitte die IP-Adresse auswählen, über die der Server von den Clients angesprochen wird.
+ </div>
+ {{#ips}}
+ <div class="panel-body">{{ip}}
+ <a class="btn btn-success" href="#" onclick="this.style.display='none';loadContent('#compiler', 'api.php?do=exec&amp;type=ipxe&amp;ip={{ip}}&amp;id=compiler')">Kompilieren</a>{{#current}} (Aktuelle Konfiguration){{/current}}
+ </div>
+ {{/ips}}
+ </div>
+ <div id="compiler">
+ </div>
+ {{^ips}}
+ <div class="alert alert-danger">Konnte lokale IP-Adressen nicht ermitteln.</div>
+ {{/ips}}
+</div>
diff --git a/templates/page-main.html b/templates/page-main.html
index 7ccf43eb..25f6cea6 100644
--- a/templates/page-main.html
+++ b/templates/page-main.html
@@ -1,6 +1,11 @@
<div class="jumbotron">
<h1>Willkommen, {{user}}</h1>
- <p>Du hast es geschafft, dich einzuloggen. Starker Typ!</p>
- <p>Du bist der Beste! Du bist der Größte! Ein Hoch auf {{user}}!</p>
+ <p>Dies ist die bwLehrpool Konfigurationsoberfläche, {{user}}</p>
+ {{#ipxe}}
+ <div class="alert alert-warning">
+ <p>Das iPXE-Modul des Servers ist veraltet oder nicht vorhanden.</p>
+ <a class="btn btn-large btn-primary" href="?do=ipxe">iPXE compilieren</a>
+ </div>
+ {{/ipxe}}
</div>
diff --git a/templates/page-minilinux.html b/templates/page-minilinux.html
new file mode 100644
index 00000000..e742f82a
--- /dev/null
+++ b/templates/page-minilinux.html
@@ -0,0 +1,24 @@
+<div class="container">
+ {{#files}}
+ <div class="panel panel-default">
+ <div class="panel-heading"><h4>
+ &raquo; {{file}}
+ {{^progress}}
+ {{#update}}
+ Neue Version! <a class="btn btn-success" href="#" onclick="this.style.display='none';loadContent('#{{id}}', 'api.php?do=download&amp;type=ml&amp;file={{file}}&amp;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>
diff --git a/templates/page-tgz-list.html b/templates/page-tgz-list.html
index 65654766..ac70d510 100644
--- a/templates/page-tgz-list.html
+++ b/templates/page-tgz-list.html
@@ -1,6 +1,6 @@
<div class="container">
{{#files}}
- <div class="row well well-sm">{{file}}</div>
+ <div class="row well well-sm">{{file}} <a class="btn btn-primary" href="?do=sysconfig&amp;action=activate&amp;file={{file}}&amp;token={{token}}">Aktivieren</a></div>
{{/files}}
{{^files}}
<div class="row well well-sm">Keine Konfigurationspakete gefunden!</div>
diff --git a/templates/txt-ipxeconfig.html b/templates/txt-ipxeconfig.html
new file mode 100644
index 00000000..df8fb90f
--- /dev/null
+++ b/templates/txt-ipxeconfig.html
@@ -0,0 +1,7 @@
+#!ipxe
+set use-cached 1
+dhcp net0
+set net0.dhcp/next-server {{{SERVER}}}
+set net0.dhcp/filename ipxelinux.0
+imgload pxelinux.0
+boot pxelinux.0
diff --git a/templates/txt-pxeconfig.html b/templates/txt-pxeconfig.html
new file mode 100644
index 00000000..6998a205
--- /dev/null
+++ b/templates/txt-pxeconfig.html
@@ -0,0 +1,68 @@
+DEFAULT vesamenu.c32
+
+NOESCAPE 1
+PROMPT 0
+
+MENU BACKGROUND openslx.png
+MENU WIDTH 78
+MENU MARGIN 9
+MENU PASSWORDMARGIN 9
+MENU ROWS 10
+MENU TABMSGROW 16
+MENU CMDLINEROW 16
+MENU ENDROW -1
+MENU PASSWORDROW 16
+MENU TIMEOUTROW 20
+MENU HELPMSGROW 16
+MENU HELPMSGENDROW -1
+MENU HSHIFT 0
+MENU VSHIFT 7
+
+menu color screen 37;40 #80ffffff #00000000 std
+menu color border 37;40 #40000000 #ff8093a1 std
+menu color title 1;37;40 #ffff8b00 #ff8093a1 std
+menu color unsel 37;40 #fff0f0f0 #ff8093a1 std
+menu color hotkey 1;37;40 #ffff8b00 #ff8093a1 std
+menu color sel 7;37;40 #ff1c2a33 #667799bb all
+menu color hotsel 1;7;37;40 #ffff8b00 #667799bb all
+menu color disabled 1;37;40 #ffff8b00 #ff8093a1 std
+menu color scrollbar 37;40 #40000000 #ee000000 std
+menu color tabmsg 37;40 #ffff8b00 #ff8093a1 std
+menu color cmdmark 1;37;40 #ffff8b00 #ff8093a1 std
+menu color cmdline 37;40 #fff0f0f0 #ff8093a1 std
+menu color pwdborder 37;40 #40000000 #ff8093a1 std
+menu color pwdheader 37;40 #ffff8b00 #ff8093a1 std
+menu color pwdentry 37;40 #ffff8b00 #ff8093a1 std
+menu color timeout_msg 37;40 #fff0f0f0 #ff8093a1 std
+menu color timeout 1;37;40 #ffff8b00 #ff8093a1 std
+menu color help 37;40 #ff1c2a33 #00000000 none
+MENU MSGCOLOR #ff1c2a33 #00000000 none
+
+
+TIMEOUT 10
+TOTALTIMEOUT 120
+MENU TITLE bwLehrpool ALPHA VERSION
+ONTIMEOUT {{{DEFAULT}}}
+
+
+
+LABEL shutdown
+ MENU HIDE
+ KERNEL kernel-shutdown
+ APPEND initrd=initramfs-shutdown quiet
+
+
+
+LABEL openslx
+ MENU LABEL bwLehrpool ^Kursumgebung
+ KERNEL http://{{{SERVER}}}/boot/default/kernel
+ INITRD http://{{{SERVER}}}/boot/default/initramfs-stage31
+ APPEND slxsrv={{{SERVER}}} slxbase=boot/default
+ IPAPPEND 3
+
+LABEL hddboot
+ MENU LABEL Von ^lokaler Festplatte booten
+ LOCALBOOT 0
+
+
+