diff options
author | Eudyptula <eitan@mosenkis.net> | 2009-06-26 12:57:57 -0400 |
---|---|---|
committer | Eudyptula <eitan@mosenkis.net> | 2009-06-26 12:57:57 -0400 |
commit | 4699a267d7099a4d42dd25c625cb50a6ff5777c7 (patch) | |
tree | be7b9b461951696ee693aa32b1262953abc114c8 | |
parent | Added signal handling and logging; wrote init script; added other nice daemon... (diff) | |
download | ingenue-4699a267d7099a4d42dd25c625cb50a6ff5777c7.tar.gz ingenue-4699a267d7099a4d42dd25c625cb50a6ff5777c7.tar.bz2 ingenue-4699a267d7099a4d42dd25c625cb50a6ff5777c7.zip |
Changed task to have an index based on build instead of unique id, added description field
-rwxr-xr-x | backend/backend.php | 2 | ||||
-rw-r--r-- | backend/functions/build.php | 17 | ||||
-rw-r--r-- | frontend/css/task.css | 19 | ||||
-rw-r--r-- | frontend/pages/logview.php | 35 | ||||
-rw-r--r-- | frontend/pages/wizard.php | 2 | ||||
-rw-r--r-- | frontend/routing.csv | 8 | ||||
-rw-r--r-- | shared/classes/build.php | 6 | ||||
-rw-r--r-- | shared/classes/buildlog.php | 33 | ||||
-rw-r--r-- | shared/classes/buildlog_entry.php (renamed from shared/classes/commandlog_entry.php) | 14 | ||||
-rw-r--r-- | shared/classes/registrationtoken.php | 1 | ||||
-rw-r--r-- | shared/classes/task.php | 53 | ||||
-rw-r--r-- | shared/include/dbinit.php | 6 | ||||
-rw-r--r-- | todo | 2 |
13 files changed, 90 insertions, 108 deletions
diff --git a/backend/backend.php b/backend/backend.php index 4d53b6d..5d5fb6b 100755 --- a/backend/backend.php +++ b/backend/backend.php @@ -46,7 +46,7 @@ if (file_put_contents($pidfile, posix_getpid())) $unlinkpidfile=true; require_once(SHARED.'/include/dbinit.php'); while (true) { - // TODO check first for builds that need to be resumed + // TODO check first for builds that need to be resumed (and figure out how to resume things) $r=$S['pdo']->query('SELECT * FROM `builds` WHERE `status`="build/ready" ORDER BY `ctime` ASC LIMIT 1'); if ($r->rowCount()) { $build=new sql_build($r->fetch(PDO::FETCH_ASSOC)); diff --git a/backend/functions/build.php b/backend/functions/build.php index df07fdc..8037913 100644 --- a/backend/functions/build.php +++ b/backend/functions/build.php @@ -35,22 +35,21 @@ function build(&$build) { 'PORTAGE_CONFIGROOT' => $C, 'PATH' => $_ENV['PATH'] ); - sql_task::execute_task('emerge --info', $build, true, null, $env); - sql_task::execute_task('emerge -p system', $build, true, null, $env); - sql_task::execute_task('emerge system', $build, true, null, $env); + sql_task::execute_command('Log portage setup', 'emerge --info', $build, true, null, $env); + sql_task::execute_command('Install base system', 'emerge system', $build, true, null, $env); if (isset($opts['install_packages'])) { $pkgs=array(); foreach (explode(' ', $opts['install_packages']) as $atom) { $pkgs[]=escapeshellarg($atom); } - sql_task::execute_task('emerge -p '.implode(' ', $pkgs), $build, true, null, $env); - foreach ($pkgs as $atom) { - sql_task::execute_task('emerge '.$atom, $build, true, null, $env); - } + if (count($pkgs) > 1) + sql_task::execute_command('Check that extra packages will install', 'emerge -p '.implode(' ', $pkgs), $build, true, null, $env); + foreach ($pkgs as $atom) + sql_task::execute_command('Install extra package '.$atom, 'emerge '.$atom, $build, true, null, $env); } - sql_task::execute_task("tar -p --same-owner -czvf '$W/image.tar.gz' -C '$W/image' .", $build, true, null, $env); + sql_task::execute_command('Compress finished image as tar/gzip', "tar -p --same-owner -czvf '$W/image.tar.gz' -C '$W/image' .", $build, true, null, $env); rename($W.'/image.tar.gz', COMPLETED.'/build-'.$build->id.'.tar.gz'); - sql_task::execute_task('rm -rf "'.$W.'"', $build, true, null, $env); + sql_task::execute_command('Delete work directory', 'rm -rf "'.$W.'"', $build, true, null, $env); return COMPLETED.'/build-'.$build->id.'.tar.gz'; } ?> diff --git a/frontend/css/task.css b/frontend/css/task.css index d3e9892..22b809a 100644 --- a/frontend/css/task.css +++ b/frontend/css/task.css @@ -1,29 +1,30 @@ -div.task { +div.task div.info { + padding-left: 2em; font-family: monospace; } -div.task span.command { +div.task div.info span.command { font-size: 110%; font-weight: bold; } -div.task span.status { +div.task div.info span.status { font-weight: bold; } -div.task span.status.successful { +div.task div.info span.status.successful { color: green; } -div.task span.status.failed { +div.task div.info span.status.failed { color: red; } -div.task span.status.running { +div.task div.info span.status.running { color: yellow; background-color: black; } -div.task span.status.queued { +div.task div.info span.status.queued { background-color: yellow } -div.task span.time span.time { +div.task div.info span.time span.time { font-weight: bold; } -div.task a { +div.task div.info a { color: blue; } diff --git a/frontend/pages/logview.php b/frontend/pages/logview.php index e8a9528..6dd9be7 100644 --- a/frontend/pages/logview.php +++ b/frontend/pages/logview.php @@ -1,36 +1,24 @@ <?php -// TODO Fix up the main builds and tasks views to display more info (especially tasks - builds will probably get removed) function init_logview() { global $S; $S['title']='Log Viewer'; } function body_logview() { global $S, $request, $conf; - if (isset($request['task']) && is_numeric($request['task'])) { - $r=$S['pdo']->query('SELECT * FROM `tasks` WHERE `id`='.$request['task']); + if (isset($request['build'], $request['task']) && preg_match('/^[a-zA-Z0-9]{6}$/', $request['build']) && is_numeric($request['task'])) { + $r=$S['pdo']->query('SELECT * FROM `tasks` WHERE `build`=\''.$request['build'].'\' AND `order`='.$request['task']); if ($r->rowCount() == 0) { - echo print_error('Not found', 'Task #'.$request['task'].' was not found.'); + echo print_error('Not found', 'Build '.$request['build'].'/task '.$request['task'].' was not found.'); return; } $task=new sql_task($r->fetch(PDO::FETCH_ASSOC)); echo '<div style="font-size: 130%">'.$task->display().'</div>'; echo '<a href="'.url('logs/build'.$task->build).'">Back</a><br/>'; -/* echo '<h3>Task '.$task->id.': '.$task->command.' '; - if (isset($task->exit)) { - if ($task->exit == 0) { - echo '<span style="color: green">[completed]</span>'; - } else { - echo '<span style="color: red">[exit status '.$task->exit.']</span>'; - } - } else { - echo '<span style="color: yellow">[running]</span>'; - } - echo '</h3>';*/ $page=isset($request['page']) && is_numeric($request['page'])?$request['page']:1; - $count=$S['pdo']->query('SELECT COUNT(*) FROM `commandlogs` WHERE `task`='.$task->id)->fetch(PDO::FETCH_COLUMN); + $count=$S['pdo']->query('SELECT COUNT(*) FROM `buildlogs` WHERE `build`=\''.$task->build.'\' AND `task`='.$task->order)->fetch(PDO::FETCH_COLUMN); $pager=''; if ($count > $conf['logview_max']) { - $pager='<form action="'.url('logs/task'.$task->id).'" method="post" onsubmit="window.location.href=\''.url('logs/task'.$task->id).'/\'+this.page.value; return false">Page: '; + $pager='<form action="'.url('logs/'.$task->build.'/'.$task->order).'" method="post" onsubmit="window.location.href=\''.url('logs/'.$task->build.'/'.$task->order).'/\'+this.page.value; return false">Page: '; if ($page > 1) { $pager.='<input type="button" value="<<" onclick="this.form.page.value='.($page-1).'; this.form.onsubmit()" /> '."\n"; } @@ -45,23 +33,23 @@ function body_logview() { $pager.='</form>'; echo $pager; } - $r=$S['pdo']->query('SELECT * FROM `commandlogs` WHERE `task`='.$task->id.' ORDER BY `order` ASC LIMIT '.$conf['logview_max'].' OFFSET '.($page-1)*$conf['logview_max']); + $r=$S['pdo']->query('SELECT * FROM `buildlogs` WHERE `build`=\''.$task->build.'\' AND `task`='.$task->order.' ORDER BY `order` ASC LIMIT '.$conf['logview_max'].' OFFSET '.($page-1)*$conf['logview_max']); if ($r->rowCount()) { echo '<div style="font-family: monospace">'; $ansi=new ansi_to_html(); while ($entry=$r->fetch(PDO::FETCH_ASSOC)) { - $entry=new sql_commandlog_entry($entry); + $entry=new sql_buildlog_entry($entry); // $text=str_replace(array("\n", "\t"), array("<br/>\n", str_repeat(' ', 4)), htmlentities($entry->text)); -// echo '<a name="entry_'.$task->id.'_'.$entry->order.'"'.($entry->stream=='stderr'?' style="color: red" ':'').' title="'.strtoupper($entry->stream).', entry #'.$entry->order.' @ '.date('D j M Y @ H:i:s', $entry->timestamp).' UTC">'.$text.'</a>'; +// echo '<a name="entry_'.$task->order.'_'.$entry->order.'"'.($entry->stream=='stderr'?' style="color: red" ':'').' title="'.strtoupper($entry->stream).', entry #'.$entry->order.' @ '.date('D j M Y @ H:i:s', $entry->timestamp).' UTC">'.$text.'</a>'; echo $ansi->process(nl2br($entry->text)); } echo $ansi->reset(); // Clear any leftover <span>s echo '</div>'; echo $pager; - echo '<a href="'.url('logs/build'.$task->build).'">Back</a><br/>'; + echo '<a href="'.url('logs/'.$task->build).'">Back</a><br/>'; } else { if ($count) { - echo print_error("There aren't $page pages. Try an <a href=\"".url('logs/task'.$task->id)."\">earlier page</a>."); + echo print_error("There aren't $page pages. Try an <a href=\"".url('logs/'.$task->build.'/'.$task->order)."\">earlier page</a>."); } else { echo print_warning('No output'); } @@ -69,7 +57,7 @@ function body_logview() { } elseif (isset($request['build']) && preg_match('/[a-z0-9]{6}/', $request['build'])) { $build=new sql_build($request['build']); echo $build->display(); - $r=$S['pdo']->query('SELECT * FROM `tasks` WHERE `build`="'.$request['build'].'" ORDER BY `id` ASC'); + $r=$S['pdo']->query('SELECT * FROM `tasks` WHERE `build`="'.$request['build'].'" ORDER BY `order` ASC'); if ($r->rowCount() == 0) { echo '<b>No tasks found.</b>'; } @@ -77,7 +65,6 @@ function body_logview() { while ($task=$r->fetch(PDO::FETCH_ASSOC)) { $task=new sql_task($task); echo $task->display(); -// echo '<a href="'.url('logs/task'.$task->id).'">Task #'.++$i.'</a>: '.htmlentities($task->command).'<br/>'; } } else { $r=$S['pdo']->query('SELECT * FROM `builds` ORDER BY `ctime` IS NULL ASC, `ctime` ASC, `status` DESC'); diff --git a/frontend/pages/wizard.php b/frontend/pages/wizard.php index bf3ca32..18797aa 100644 --- a/frontend/pages/wizard.php +++ b/frontend/pages/wizard.php @@ -79,7 +79,7 @@ function body_wizard() { global $S; if (isset($S['wizard.build'])) { if (isset($S['wizard.done'])) { - echo '<h3>Config finished!</h3><p>Check your build\'s status <a href="'.url('logs/build'.$S['wizard.build']->id).'">here</a></p>'; + echo '<h3>Config finished!</h3><p>Check your build\'s status <a href="'.url('logs/'.$S['wizard.build']->id).'">here</a></p>'; } else { $build=&$S['wizard.build']; $step=&$S['wizard.step']; diff --git a/frontend/routing.csv b/frontend/routing.csv index 4baf180..74c9fee 100644 --- a/frontend/routing.csv +++ b/frontend/routing.csv @@ -13,10 +13,10 @@ ^$ welcome # Logs ^logs$ logview -^logs/build([a-z0-9]{6})$ logview build -^logs/build([a-z0-9]{6})/live$ livelog build -^logs/task([0-9]+)$ logview task -^logs/task([0-9]+)/([0-9]+)$ logview task page +^logs/([a-z0-9]{6})$ logview build +^logs/([a-z0-9]{6})/([0-9]+)$ logview build task +^logs/([a-z0-9]{6})/([0-9]+)/([0-9]+)$ logview build task page +#^logs/([a-z0-9]{6})/live$ livelog build # Build creation ^create$ wizard ^create/([a-zA-Z0-9]{6})$ wizard build diff --git a/shared/classes/build.php b/shared/classes/build.php index 369425e..fd02aa9 100644 --- a/shared/classes/build.php +++ b/shared/classes/build.php @@ -90,16 +90,16 @@ class sql_build extends sql_row_obj { } elseif ($status[1]='running') { // Add link to regular log viewer? // Build stage X - $html.='<span class="status building">[building]</span><br/><span class="links"><a href="'.url('logs/build'.$this->id.'/live').'">Watch</a></span>'; + $html.='<span class="status building">[building]</span><br/><span class="links"><a href="'.url('logs/'.$this->id.'/live').'">Watch</a></span>'; } else { throw_exception('Unrecognized build status '.$this->status); } } elseif ($status[0] == 'finished') { $status=explode(': ', $status[1], 2); if ($status[0] == 'success') { - $html.='<span class="status successful">[successful]</span><br/><span class="links"><a href="'.url('download/'.$this->id).'">Download image</a> • <a href="'.url('logs/build'.$this->id).'">Build log</a></span>'; + $html.='<span class="status successful">[successful]</span><br/><span class="links"><a href="'.url('download/'.$this->id).'">Download image</a> • <a href="'.url('logs/'.$this->id).'">Build log</a></span>'; } elseif ($status[0] == 'failed') { - $html.='<span class="status failed">[failed: '.htmlentities($status[1]).']</span><br/><span class="links"><a href="'.url('logs/build'.$this->id.'/failure').'">View output of failed command</a> • <a href="'.url('logs/build'.$this->id).'">Build log</a></span>'; + $html.='<span class="status failed">[failed: '.htmlentities($status[1]).']</span><br/><span class="links"><a href="'.url('logs/'.$this->id.'/failure').'">View output of failed command</a> • <a href="'.url('logs/'.$this->id).'">Build log</a></span>'; } else { throw_exception('Unrecognized build status '.$this->status); } diff --git a/shared/classes/buildlog.php b/shared/classes/buildlog.php deleted file mode 100644 index 5ba95f6..0000000 --- a/shared/classes/buildlog.php +++ /dev/null @@ -1,33 +0,0 @@ -<?php -class sql_buildlog extends sql_row_obj { - protected $table='buildlogs', $primary_key=array('build', 'order'), $columns=array( - 'build' => array ( - 'type' => 'CHAR', - 'length' => 6, - 'not_null' => true, - 'default' => '' - ), - 'order' => array ( - 'type' => 'TINYINT', - 'length' => 3, - 'unsigned' => true, - 'not_null' => true, - 'default' => 0 - ), - 'type' => array ( - 'type' => 'ENUM', - 'length' => '\'command\',\'system\',\'msg\'', - 'not_null' => true - ), - 'id' => array ( - 'type' => 'INT', - 'length' => 10, - 'unsigned' => true - ), - 'msg' => array ( - 'type' => 'TEXT' - ) - - ); -} -?> diff --git a/shared/classes/commandlog_entry.php b/shared/classes/buildlog_entry.php index 5f78aab..5b8c380 100644 --- a/shared/classes/commandlog_entry.php +++ b/shared/classes/buildlog_entry.php @@ -1,9 +1,15 @@ <?php -class sql_commandlog_entry extends sql_row_obj { - protected $table='commandlogs', $columns=array( +class sql_buildlog_entry extends sql_row_obj { + protected $table='buildlogs', $primary_key=array('build', 'task', 'order'), $columns=array( + 'build' => array ( + 'type' => 'CHAR', + 'length' => 6, + 'not_null' => true, + 'default' => '' + ), 'task' => array ( - 'type' => 'INT', - 'length' => 10, + 'type' => 'TINYINT', + 'length' => 3, 'unsigned' => true, 'not_null' => true, 'default' => 0 diff --git a/shared/classes/registrationtoken.php b/shared/classes/registrationtoken.php index 86e8d44..9f331ae 100644 --- a/shared/classes/registrationtoken.php +++ b/shared/classes/registrationtoken.php @@ -16,6 +16,7 @@ class sql_registrationtoken extends sql_row_obj { 'type' => 'VARCHAR', 'length' => 255, 'not_null' => true, + 'default' => '', 'unique' => true ), 'expire' => array ( diff --git a/shared/classes/task.php b/shared/classes/task.php index ba8db5e..2fb7c68 100644 --- a/shared/classes/task.php +++ b/shared/classes/task.php @@ -1,13 +1,6 @@ <?php class sql_task extends sql_row_obj { - protected $table='tasks', $primary_key=array('id'), $columns=array( - 'id' => array ( - 'type' => 'INT', - 'length' => 10, - 'unsigned' => true, - 'not_null' => true, - 'auto_increment' => true - ), + protected $table='tasks', $primary_key=array('build', 'order'), $columns=array( 'build' => array ( 'type' => 'CHAR', 'length' => 6, @@ -15,6 +8,23 @@ class sql_task extends sql_row_obj { 'default' => '', 'refers_to' => 'builds.id' ), + 'order' => array ( + 'type' => 'TINYINT', + 'length' => 4, + 'not_null' => true, + 'default' => 0 + ), + 'type' => array ( + 'type' => 'ENUM', + 'length' => '\'exec\',\'internal\'', + 'not_null' => true + ), + 'description' => array ( + 'type' => 'VARCHAR', + 'length' => 255, + 'not_null' => true, + 'default' => '' + ), 'command' => array ( 'type' => 'TEXT', 'not_null' => true @@ -36,7 +46,7 @@ class sql_task extends sql_row_obj { ); function display() { - $html='<div class="task">[<a href="'.url('logs/task'.$this->id).'">log</a>] <span class="command">'.htmlentities($this->command).'</span> '; + $html='<div class="task"><div class="description">'.htmlentities($this->description).'</div><div class="info">[<a href="'.url('logs/'.$this->build.'/'.$this->order).'">log</a>] <span class="command">'.htmlentities($this->command).'</span> '; if (isset($this->start)) { if (isset($this->finish)) { $html.='<span class="status '; @@ -57,18 +67,19 @@ class sql_task extends sql_row_obj { } } else { $total=$S['pdo']->query('SELECT COUNT(*) FROM `tasks` WHERE `build`="'.$this->build.'" AND `start` IS NULL')->fetch(PDO::FETCH_COLUMN); - $num=$S['pdo']->query('SELECT COUNT(*) FROM `tasks` WHERE `builds`="'.$this->build.'" AND `start` IS NULL AND `id` <= '.$this->id); + $num=$S['pdo']->query('SELECT COUNT(*) FROM `tasks` WHERE `builds`="'.$this->build.'" AND `start` IS NULL AND `order` <= '.$this->order); $html.="<span class=\"status queued\">[queued $num/$total]</span>"; } - $html.='</div>'; + $html.='</div></div>'; return $html; } function execute($fatal=true, $path=null, $env=null) { - if (!isset($this->command, $this->build)) { - throw_exception('$this->command or $this->build not set'); + if (!isset($this->command, $this->build, $this->order)) { + throw_exception('$this->command, $this->build, or $this->order not set'); } elseif (isset($this->start)) { throw_exception('task has already executed: start is '.$this->start); } + $this->type='exec'; log_msg('Executing '.$this->command.'...', false); $descriptorspec=array( 0 => array('pipe', 'r'), // STDIN @@ -91,13 +102,13 @@ class sql_task extends sql_row_obj { $c=stream_get_contents($pipes[2]); if ($c) { // STDERR - $entry=new sql_commandlog_entry($this->id, $msg++, time(), 'stderr', $c); + $entry=new sql_buildlog_entry($this->build, $this->order, $msg++, time(), 'stderr', $c); $entry->write(); } $c=stream_get_contents($pipes[1]); if ($c) { // STDOUT - $entry=new sql_commandlog_entry($this->id, $msg++, time(), 'stdout', $c); + $entry=new sql_buildlog_entry($this->build, $this->order, $msg++, time(), 'stdout', $c); $entry->write(); } } @@ -140,10 +151,18 @@ class sql_task extends sql_row_obj { } return $this->exit; } - static function execute_task($command, $build, $fatal=true, $path=null, $env=null) { + static function execute_command($description, $command, $build, $fatal=true, $path=null, $env=null) { global $task; - $task=new sql_task(null, is_object($build)?$build->id:$build, $command); + // TODO this won't work once we have internal tasks too - we need to modify the build class to track its own task IDs + static $buildid=null; + static $order=0; + if ($build->id !== $buildid) { + $buildid=$build->id; + $order=0; + } + $task=new sql_task($build->id, $order, null, $description, $command); $result=$task->execute($fatal, $path, $env); + $order++; unset($task); return $result; } diff --git a/shared/include/dbinit.php b/shared/include/dbinit.php index 3b19689..e52498a 100644 --- a/shared/include/dbinit.php +++ b/shared/include/dbinit.php @@ -1,7 +1,11 @@ <?php require_once(dirname(__FILE__).'/../config.php'); // Use __DIR__ in 5.3.0 $pdoclass=(class_exists('pdo_debug')?'pdo_debug':'PDO'); -$S['pdo']=new $pdoclass('mysql:dbname='.$conf['sqldb'].';host='.$conf['sqlhost'], $conf['sqluser'], $conf['sqlpass']); +try { + $S['pdo']=new $pdoclass('mysql:dbname='.$conf['sqldb'].';host='.$conf['sqlhost'], $conf['sqluser'], $conf['sqlpass'], array(PDO::ATTR_PERSISTENT => true)); +} catch (Exception $e) { + die(print_error('Database connection failure.', $e->getMessage())); +} unset($pdoclass); sql_row_obj::set_pdo_obj($S['pdo']); ?> @@ -9,8 +9,6 @@ Add logging besides just commands (restructure the buildlogs table) Make backend do a dummy run through and queue all commands and other tasks, then execute them (for better status handling, easier debugging, etc.) Have builds and tasks not give links to logs if we're already viewing the logs Either make task status a TEXT or stop putting command name in the status (via thrown exception) - we can fetch this later anyway - just store the task id that failed (or use the last task) -Remove the auto_increment on tasks and change it to just increment itself based on build -Add a description to tasks so in the logs they say "Install base system" instead of "emerge system" Consider saving env. passed to tasks, path if we ever use it Add metadata back to logviewer Do like wikipedia and put the header in the footer so important parts load first |