18 Commits

Author SHA1 Message Date
8d2ca716df Updated worker to copy rather than move output to final location
This causes ACLs to be inherited from the destination, rather than
preserving permissions from the temporary build location on the local
machine.
2011-08-20 11:07:30 +01:00
47946bcf98 Update handbrake backend to rip to temp dir 2011-08-07 15:40:17 +01:00
d2b2dc7925 Add output filesize to jobs summary page 2011-08-06 23:11:15 +01:00
e84c1eba42 Set logging program name 2011-08-06 14:57:14 +01:00
b93efc9878 Replace if block with switch case for extensibility 2011-08-06 14:55:29 +01:00
9697654594 Propagate changes to logging system from framework library 2011-08-06 14:54:22 +01:00
5121f78cea Merge branch 'master' of git+ssh://git.sihnon.net/home/git/public/handbrake-cluster-webui 2011-08-05 19:40:42 +01:00
dbc1252bef Added config file override for worker script 2011-08-05 19:35:55 +01:00
a3e58e4ee4 Merge branch 'master' of git+ssh://git.sihnon.net/home/git/public/handbrake-cluster-webui 2011-06-28 20:11:50 +01:00
3b22b0f2c9 Bug fix: Undefined index $values[9]
RippingCluster_LogEntry overwrote base class field list, causing
undefined index notices when the base class was explicitly used.
2011-06-28 20:06:24 +01:00
efb7db35d8 Fixed typo in _inc.php 2011-06-20 22:33:18 +01:00
841a5b9f92 Revert previous untested change in include statements 2011-06-20 22:04:44 +01:00
506a6e189c Update paths for packaging 2011-06-20 19:34:27 +01:00
3da59727de Bug fix: typo in variable name 2011-06-20 19:29:11 +01:00
c0d8747b21 Update init script to background the worker process 2011-06-19 22:48:45 +01:00
e1bd324e84 Bugfix: error in client log call 2011-06-19 00:13:39 +01:00
8fe8f8ba08 Use defines for library paths 2011-06-18 23:53:25 +01:00
274bc8f3c9 Use defines for library paths 2011-06-18 22:15:36 +01:00
10 changed files with 114 additions and 45 deletions

View File

@@ -12,7 +12,7 @@ depend() {
start() { start() {
ebegin "Starting ripping-cluster-worker" ebegin "Starting ripping-cluster-worker"
start-stop-daemon --start --quiet \ start-stop-daemon --start --quiet \
--pidfile ${PID_FILE} \ --background --make-pidfile --pidfile ${PID_FILE} \
--exec /usr/bin/php /usr/lib/ripping-cluster/worker/ripping-cluster-worker.php --exec /usr/bin/php /usr/lib/ripping-cluster/worker/ripping-cluster-worker.php
eend $? "Failed to start ripping-cluster-worker" eend $? "Failed to start ripping-cluster-worker"
} }

View File

@@ -30,11 +30,14 @@ class Net_Gearman_Job_HandBrake extends Net_Gearman_Job_Common implements Rippin
$this->job = RippingCluster_Job::fromId($args['rip_options']['id']); $this->job = RippingCluster_Job::fromId($args['rip_options']['id']);
// Substitute a temporary output filename into the rip options
$args['temp_output_filename'] = tempnam($config->get('rips.temp_dir', '/tmp'), 'hbr_');
$handbrake_cmd_raw = array( $handbrake_cmd_raw = array(
'-n', $config->get('rips.nice'), '-n', $config->get('rips.nice'),
$config->get('rips.handbrake_binary'), $config->get('rips.handbrake_binary'),
self::evaluateOption($args['rip_options'], 'input_filename', '-i'), self::evaluateOption($args['rip_options'], 'input_filename', '-i'),
self::evaluateOption($args['rip_options'], 'output_filename', '-o'), self::evaluateOption($args, 'temp_output_filename', '-o'),
self::evaluateOption($args['rip_options'], 'title'), self::evaluateOption($args['rip_options'], 'title'),
self::evaluateOption($args['rip_options'], 'format', '-f'), self::evaluateOption($args['rip_options'], 'format', '-f'),
self::evaluateOption($args['rip_options'], 'video_codec', '-e'), self::evaluateOption($args['rip_options'], 'video_codec', '-e'),
@@ -61,12 +64,34 @@ class Net_Gearman_Job_HandBrake extends Net_Gearman_Job_Common implements Rippin
list($return_val, $stdout, $stderr) = RippingCluster_ForegroundTask::execute($handbrake_cmd, null, null, null, array($this, 'callbackOutput'), array($this, 'callbackOutput'), $this); list($return_val, $stdout, $stderr) = RippingCluster_ForegroundTask::execute($handbrake_cmd, null, null, null, array($this, 'callbackOutput'), array($this, 'callbackOutput'), $this);
if ($return_val) { if ($return_val) {
// Remove any temporary output files
if (file_exists($args['temp_output_filename'])) {
$result = unlink($args['temp_output_filename']);
if ($result) {
RippingCluster_WorkerLogEntry::warning($log, $this->job->id(), "Failed to remove temporary output file, still exists at '{$args['temp_output_filename']}'.");
}
}
$this->fail($return_val); $this->fail($return_val);
} else { } else {
$this->job->updateStatus(RippingCluster_JobStatus::COMPLETE); // Copy the temporary output file to the desired destination
$this->complete( array( $move = copy($args['temp_output_filename'], $args['rip_options']['output_filename']);
'id' => $this->job->id() if ($move) {
)); // Remove the temporary output file
$result = unlink($args['temp_output_filename']);
if ($result) {
RippingCluster_WorkerLogEntry::warning($log, $this->job->id(), "Failed to remove temporary output file, still exists at '{$args['temp_output_filename']}'.");
}
//Report success
$this->job->updateStatus(RippingCluster_JobStatus::COMPLETE);
$this->complete( array(
'id' => $this->job->id()
));
} else {
RippingCluster_WorkerLogEntry::error($log, $this->job->id(), "Failed to copy temporary output file to proper destination. File retained as '{$args['temp_output_filename']}'.");
$this->job->updateStatus(RippingCluster_JobStatus::FAILED);
$this->fail('-1');
}
} }
} }

View File

@@ -271,7 +271,20 @@ class RippingCluster_Job {
return $new_status; return $new_status;
} }
public function isFinished() {
$current_status = $this->currentStatus()->status();
return ($current_status == RippingCluster_JobStatus::COMPLETE || $current_status == RippingCluster_JobStatus::FAILED);
}
public function outputFilesize() {
if (file_exists($this->destination_filename)) {
return filesize($this->destination_filename);
}
return null;
}
public function calculateETA() { public function calculateETA() {
$current_status = $this->currentStatus(); $current_status = $this->currentStatus();
if ($current_status->status() != RippingCluster_JobStatus::RUNNING) { if ($current_status->status() != RippingCluster_JobStatus::RUNNING) {

View File

@@ -4,12 +4,20 @@ class RippingCluster_LogEntry extends SihnonFramework_LogEntry {
protected $job_id; protected $job_id;
protected static $types;
public static function initialise() { public static function initialise() {
self::$types['job_id'] = 'int'; // Copy the list of datatypes from the parent
// We can't modify it in place, else we'll break any logging done inside the SihnonFramework tree
// or other subclass trees.
static::$types = parent::$types;
// Add the new data types for this subclass
static::$types['job_id'] = 'int';
} }
protected function __construct($level, $category, $ctime, $pid, $file, $line, $message, $job_id) { protected function __construct($level, $category, $ctime, $hostname, $progname, $pid, $file, $line, $message, $job_id) {
parent::__construct($level, $category, $ctime, $pid, $file, $line, $message); parent::__construct($level, $category, $ctime, $hostname, $progname, $pid, $file, $line, $message);
$this->job_id = $job_id; $this->job_id = $job_id;
} }
@@ -19,6 +27,8 @@ class RippingCluster_LogEntry extends SihnonFramework_LogEntry {
$row['level'], $row['level'],
$row['category'], $row['category'],
$row['ctime'], $row['ctime'],
$row['hostname'],
$row['progname'],
$row['pid'], $row['pid'],
$row['file'], $row['file'],
$row['line'], $row['line'],
@@ -32,8 +42,8 @@ class RippingCluster_LogEntry extends SihnonFramework_LogEntry {
$this->level, $this->level,
$this->category, $this->category,
$this->ctime, $this->ctime,
static::$hostname, $this->hostname,
static::$progname, $this->progname,
$this->pid, $this->pid,
$this->file, $this->file,
$this->line, $this->line,
@@ -48,7 +58,7 @@ class RippingCluster_LogEntry extends SihnonFramework_LogEntry {
protected static function log($logger, $severity, $job_id, $message, $category = SihnonFramework_Log::CATEGORY_DEFAULT) { protected static function log($logger, $severity, $job_id, $message, $category = SihnonFramework_Log::CATEGORY_DEFAULT) {
$backtrace = debug_backtrace(false); $backtrace = debug_backtrace(false);
$entry = new self($severity, $category, time(), getmypid(), $backtrace[1]['file'], $backtrace[1]['line'], $message, $job_id); $entry = new self($severity, $category, time(), static::$localHostname, static::$localProgname, getmypid(), $backtrace[1]['file'], $backtrace[1]['line'], $message, $job_id);
$logger->log($entry); $logger->log($entry);
} }

View File

@@ -11,24 +11,29 @@ class RippingCluster_Main extends SihnonFramework_Main {
protected function __construct() { protected function __construct() {
parent::__construct(); parent::__construct();
$request_string = isset($_GET['l']) ? $_GET['l'] : '';
$this->request = new RippingCluster_RequestParser($request_string);
if (HBC_File == 'index') {
$this->smarty = new Smarty();
$this->smarty->template_dir = './source/templates';
$this->smarty->compile_dir = './tmp/templates';
$this->smarty->cache_dir = './tmp/cache';
$this->smarty->config_dir = './config';
$this->smarty->registerPlugin('modifier', 'formatDuration', array('RippingCluster_Main', 'formatDuration'));
$this->smarty->assign('version', '0.1'); $request_string = isset($_GET['l']) ? $_GET['l'] : '';
$this->smarty->assign('messages', array());
$this->request = new RippingCluster_RequestParser($request_string);
$this->smarty->assign('base_uri', $this->base_uri);
switch (HBC_File) {
case 'index': {
$smarty_tmp = '/tmp/ripping-cluster';
$this->smarty = new Smarty();
$this->smarty->template_dir = static::makeAbsolutePath('./source/templates');
$this->smarty->compile_dir = static::makeAbsolutePath($smarty_tmp . '/tmp/templates');
$this->smarty->cache_dir = static::makeAbsolutePath($smarty_tmp . '/tmp/cache');
$this->smarty->config_dir = static::makeAbsolutePath($smarty_tmp . '/config');
$this->smarty->registerPlugin('modifier', 'formatDuration', array('RippingCluster_Main', 'formatDuration'));
$this->smarty->registerPlugin('modifier', 'formatFilesize', array('RippingCluster_Main', 'formatFilesize'));
$this->smarty->assign('version', '0.1');
$this->smarty->assign('messages', array());
$this->smarty->assign('base_uri', $this->base_uri);
} break;
} }
} }
@@ -37,14 +42,14 @@ class RippingCluster_Main extends SihnonFramework_Main {
} }
/** /**
* *
* @return RippingCluster_RequestParser * @return RippingCluster_RequestParser
*/ */
public function request() { public function request() {
return $this->request; return $this->request;
} }
} }
?> ?>

View File

@@ -1,10 +1,9 @@
<?php <?php
require_once '../private/config.php'; require_once '/etc/ripping-cluster/config.php';
require_once(SihnonFramework_Lib . 'SihnonFramework/Main.class.php'); require_once SihnonFramework_Lib . 'SihnonFramework/Main.class.php';
//require_once RippingCluster_Lib . 'RippingCluster/Main.class.php';
SihnonFramework_Main::registerAutoloadClasses('SihnonFramework', SihnonFramework_Lib, SihnonFramework_Main::registerAutoloadClasses('SihnonFramework', SihnonFramework_Lib,
'RippingCluster', SihnonFramework_Main::makeAbsolutePath('../source/lib/')); 'RippingCluster', RippingCluster_Lib);
?> ?>

View File

@@ -6,6 +6,7 @@ require '_inc.php';
try { try {
$main = RippingCluster_Main::instance(); $main = RippingCluster_Main::instance();
RippingCluster_LogEntry::setLocalProgname('webui');
$smarty = $main->smarty(); $smarty = $main->smarty();
$page = new RippingCluster_Page($smarty, $main->request()); $page = new RippingCluster_Page($smarty, $main->request());

View File

@@ -2,12 +2,12 @@
define('HBC_File', 'run-jobs'); define('HBC_File', 'run-jobs');
require_once '../private/config.php'; require_once '/etc/ripping-cluster/config.php';
require_once(SihnonFramework_Lib . 'SihnonFramework/Main.class.php'); require_once(SihnonFramework_Lib . 'SihnonFramework/Main.class.php');
require_once 'Net/Gearman/Client.php'; require_once 'Net/Gearman/Client.php';
SihnonFramework_Main::registerAutoloadClasses('SihnonFramework', SihnonFramework_Lib, SihnonFramework_Main::registerAutoloadClasses('SihnonFramework', SihnonFramework_Lib,
'RippingCluster', SihnonFramework_Main::makeAbsolutePath('../source/lib/')); 'RippingCluster', RippingCluster_Lib);
try { try {
$main = RippingCluster_Main::instance(); $main = RippingCluster_Main::instance();
@@ -34,7 +34,7 @@ try {
// Start the job queue // Start the job queue
$result = $client->runSet($set); $result = $client->runSet($set);
RippingCluster_LogEntry::info($log, 'Job queue completed', 'batch'); RippingCluster_ClientLogEntry::info($log, null, 'Job queue completed', 'batch');
} catch (RippingCluster_Exception $e) { } catch (RippingCluster_Exception $e) {
die("Uncaught Exception (" . get_class($e) . "): " . $e->getMessage() . "\n"); die("Uncaught Exception (" . get_class($e) . "): " . $e->getMessage() . "\n");
@@ -55,7 +55,7 @@ function gearman_fail($task) {
$main = RippingCluster_Main::instance(); $main = RippingCluster_Main::instance();
$log = $main->log(); $log = $main->log();
$job = RippingCluster_Job::fromId($task->args['rip_options']['id']); $job = RippingCluster_Job::fromId($task->arg['rip_options']['id']);
$job->updateStatus(RippingCluster_JobStatus::FAILED); $job->updateStatus(RippingCluster_JobStatus::FAILED);
RippingCluster_ClientLogEntry::info($log, $job->id(), 'Job failed'); RippingCluster_ClientLogEntry::info($log, $job->id(), 'Job failed');

View File

@@ -43,7 +43,12 @@
{assign var=current_status value=$job->currentStatus()} {assign var=current_status value=$job->currentStatus()}
<tr> <tr>
<td><a href="{$base_uri}job-details/id/{$job->id()}" title="View job details">{$job->name()}</a></td> <td><a href="{$base_uri}job-details/id/{$job->id()}" title="View job details">{$job->name()}</a></td>
<td>{$job->destinationFilename()}</td> <td>
{$job->destinationFilename()}
{if $job->isFinished()}
({$job->outputFilesize()|formatFilesize})
{/if}
</td>
<td>{$job->title()}</td> <td>{$job->title()}</td>
<td> <td>
{$current_status->statusName()} {$current_status->statusName()}

View File

@@ -2,13 +2,23 @@
define('HBC_File', 'worker'); define('HBC_File', 'worker');
require_once '/etc/ripping-cluster/config.php'; $options = array();
if (isset($_SERVER['argv'])) {
$options = getopt('c:', array('config:'));
}
if (isset($options['config'])) {
require_once $options['config'];
} else {
require_once '/etc/ripping-cluster/config.php';
}
require_once(SihnonFramework_Lib . 'SihnonFramework/Main.class.php'); require_once(SihnonFramework_Lib . 'SihnonFramework/Main.class.php');
require_once 'Net/Gearman/Worker.php'; require_once 'Net/Gearman/Worker.php';
SihnonFramework_Main::registerAutoloadClasses('SihnonFramework', SihnonFramework_Lib, SihnonFramework_Main::registerAutoloadClasses('SihnonFramework', SihnonFramework_Lib,
'RippingCluster', SihnonFramework_Main::makeAbsolutePath('../source/lib/')); 'RippingCluster', SihnonFramework_Main::makeAbsolutePath(RippingCluster_Lib));
SihnonFramework_Main::registerAutoloadClasses('Net', SihnonFramework_Main::makeAbsolutePath('../source/lib/')); SihnonFramework_Main::registerAutoloadClasses('Net', SihnonFramework_Main::makeAbsolutePath(RippingCluster_Lib));
try { try {
@@ -16,6 +26,7 @@ try {
set_time_limit(0); set_time_limit(0);
$main = RippingCluster_Main::instance(); $main = RippingCluster_Main::instance();
RippingCluster_LogEntry::setLocalProgname('ripping-cluster-worker');
$smarty = $main->smarty(); $smarty = $main->smarty();
$worker = new RippingCluster_Worker(); $worker = new RippingCluster_Worker();