From 65aa04a69a24664ff2c952b5baf46f83ce301d88 Mon Sep 17 00:00:00 2001 From: Jeroen De Meerleer Date: Tue, 1 Jun 2021 13:45:57 +0200 Subject: [PATCH] Failed runs are now saved per run instead of based on global response code --- src/Command/DaemonCommand.php | 12 ++++----- src/Controller/JobController.php | 2 +- src/Repository/Job.php | 46 ++++++++++++++++++++------------ src/Repository/Run.php | 24 ++++++++++------- storage/database.sql | 3 ++- templates/job/view.html.twig | 3 +++ 6 files changed, 56 insertions(+), 34 deletions(-) diff --git a/src/Command/DaemonCommand.php b/src/Command/DaemonCommand.php index 25baf86..b0748e1 100644 --- a/src/Command/DaemonCommand.php +++ b/src/Command/DaemonCommand.php @@ -49,20 +49,20 @@ class DaemonCommand extends Command $jobsToRun = $jobRepo->getJobsDue(); if(!empty($jobsToRun)) { foreach($jobsToRun as $job) { - $jobRepo->setJobRunning($job, true); - $output->writeln('Running Job ' . $job); + $jobRepo->setJobRunning($job['id'], true); + $output->writeln('Running Job ' . $job['id']); declare(ticks = 1); pcntl_signal(SIGCHLD, SIG_IGN); $pid = pcntl_fork(); if($pid == -1) { - $jobRepo->RunJob($job); - $jobRepo->setJobRunning($job, false); + $jobRepo->RunJob($job['id'], $job['running'] == 2); + $jobRepo->setJobRunning($job['id'], false); } elseif ($pid == 0) { $dbcon = $this->kernel->getDbCon(); $dbcon->close(); $dbcon->connect(); - $jobRepo->RunJob($job); - $jobRepo->setJobRunning($job, false); + $jobRepo->RunJob($job['id'], $job['running'] == 2); + $jobRepo->setJobRunning($job['id'], false); exit; } diff --git a/src/Controller/JobController.php b/src/Controller/JobController.php index 13f1e54..c4eb48c 100644 --- a/src/Controller/JobController.php +++ b/src/Controller/JobController.php @@ -32,7 +32,7 @@ class JobController extends Controller if($this->getRequest()->getMethod() == 'GET') { $job = $jobRepo->getJob($id); - $runs = $runRepo->getRunsForJob($id, $all != 'all' ? array_merge($job['data']['response'] ?? [], $job['data']['http-status'] ?? []) : []); + $runs = $runRepo->getRunsForJob($id, $all != 'all'); return $this->render('job/view.html.twig', ['job' => $job, 'runs' => $runs, 'allruns' => $all == 'all']); } elseif($this->getRequest()->getMethod() == 'DELETE') { $success = $jobRepo->deleteJob($id); diff --git a/src/Repository/Job.php b/src/Repository/Job.php index e0cc690..459c0d0 100644 --- a/src/Repository/Job.php +++ b/src/Repository/Job.php @@ -38,7 +38,7 @@ class Job extends Repository public function getJobsDue() { - $jobsSql = "SELECT id + $jobsSql = "SELECT id, running FROM job WHERE ( nextrun <= :timestamp @@ -49,11 +49,7 @@ class Job extends Repository $jobsStmt = $this->dbcon->prepare($jobsSql); $jobsRslt = $jobsStmt->executeQuery([':timestamp' => time(), ':timestamplastrun' => time(), ':timestamprun' => time()]); $jobs = $jobsRslt->fetchAllAssociative(); - $return = []; - foreach ($jobs as $job) { - $return[] = $job['id']; - } - return $return; + return $jobs; } public function setJobRunning(int $job, bool $status): void @@ -117,9 +113,9 @@ class Job extends Repository $options['http_errors'] = false; $options['auth'] = !empty($job['data']['basicauth-username']) ? [$job['data']['basicauth-username'], $job['data']['basicauth-password']] : NULL; $res = $client->request('GET', $url, $options); - $return['exitcode'] = $res->getStatusCode(); $return['output'] = $res->getBody(); + $return['failed'] = !in_array($return['exitcode'], $job['data']['http-status']); return $return; } @@ -136,9 +132,13 @@ class Job extends Repository $command = $this->prepareDockerCommand($command, $job['data']['service'], $job['data']['container-user']); } if($job['data']['hosttype'] == 'local') { - return $this->runLocalCommand($command); + $return = $this->runLocalCommand($command); + $return['failed'] = !in_array($return['exitcode'], $job['data']['http-status']); + return $return; } elseif($job['data']['hosttype'] == 'ssh') { - return $this->runSshCommand($command, $job['data']['host'], $job['data']['user'], $job['data']['ssh-privkey'], $job['data']['privkey-password']); + $return = $this->runSshCommand($command, $job['data']['host'], $job['data']['user'], $job['data']['ssh-privkey'], $job['data']['privkey-password']); + $return['failed'] = !in_array($return['exitcode'], $job['data']['http-status']); + return $return; } } @@ -178,10 +178,11 @@ class Job extends Repository return $return; } - private function runRebootJob(array $job, float &$starttime): array + private function runRebootJob(array $job, float &$starttime, bool &$manual): array { if($job['running'] == 1) { $this->setTempVar($job['id'], 'starttime', $starttime); + $this->setTempVar($job['id'], 'manual', $manual); $job['data']['reboot-command'] = str_replace('{reboot-delay}', $job['data']['reboot-delay'], $job['data']['reboot-command']); $job['data']['reboot-command'] = str_replace('{reboot-delay-secs}', $job['data']['reboot-delay-secs'], $job['data']['reboot-command']); @@ -209,6 +210,8 @@ class Job extends Repository } $starttime = (float)$this->getTempVar($job['id'], 'starttime'); $this->deleteTempVar($job['id'], 'starttime'); + $manual = (float)$this->getTempVar($job['id'], 'manual'); + $this->deleteTempVar($job['id'], 'manual'); $jobsSql = "UPDATE job SET running = :status WHERE id = :id"; $jobsStmt = $this->dbcon->prepare($jobsSql); @@ -237,7 +240,7 @@ class Job extends Repository return $prepend . $command; } - public function runJob(int $job): void + public function runJob(int $job, bool $manual): void { $starttime = microtime(true); $job = $this->getJob($job, true); @@ -246,16 +249,25 @@ class Job extends Repository } elseif($job['data']['crontype'] == 'command') { $result = $this->runCommandJob($job); } elseif($job['data']['crontype'] == 'reboot') { - $result = $this->runRebootJob($job, $starttime); + $result = $this->runRebootJob($job, $starttime, $manual); } $endtime = microtime(true); $runtime = $endtime - $starttime; - // handling of response - $addRunSql = 'INSERT INTO run(job_id, exitcode, output, runtime, timestamp) VALUES (:job_id, :exitcode, :output, :runtime, :timestamp)'; - $addRunStmt = $this->dbcon->prepare($addRunSql); - $addRunStmt->executeQuery([':job_id' => $job['id'], ':exitcode' => $result['exitcode'], ':output' => $result['output'], ':runtime' => $runtime, ':timestamp' => floor($starttime)]); + // setting flags + $flags = []; + if($result['failed'] === true) { + $flags[] = Run::FAILED; + } else { + $flags[] = Run::SUCCESS; + } + if($manual === true) { + $flags[] = Run::MANUAL; + } + // saving to database + $runRepo = new Run($this->dbcon); + $runRepo->addRun($job['id'], $result['exitcode'], floor($starttime), $runtime, $result['output'], $flags); // setting nextrun to next run $nextrun = $job['nextrun']; do { @@ -270,7 +282,7 @@ class Job extends Repository public function unlockJob(int $id = 0): void { - $jobsSql = "UPDATE job SET running = :status WHERE running IN (0,1,2)"; + $jobsSql = "UPDATE job SET running = :status WHERE running = 1"; $params = [':status' => 0]; if($id != 0) { diff --git a/src/Repository/Run.php b/src/Repository/Run.php index cb2689e..e1dc02d 100644 --- a/src/Repository/Run.php +++ b/src/Repository/Run.php @@ -8,18 +8,16 @@ use JeroenED\Framework\Repository; class Run extends Repository { - public function getRunsForJob(int $id, $excludedexitcodes = [], $ordered = true): array + const FAILED = 'F'; + const SUCCESS = 'S'; + const MANUAL = 'M'; + + public function getRunsForJob(int $id, $failed = true, $ordered = true): array { $runsSql = "SELECT * FROM run WHERE job_id = :job"; $params = [':job' => $id]; - if (!empty($excludedexitcodes)) { - $runsSql .= ' AND exitcode NOT in '; - $exitcodes = []; - foreach($excludedexitcodes as $key => $exitcode) { - $exitcodes[] = ':code' . $key; - $params[':code' . $key] = $exitcode; - } - $runsSql .= '(' . implode(',', $exitcodes) . ')'; + if ($failed) { + $runsSql .= ' AND flags LIKE "%' . Run::FAILED . '%"'; } if ($ordered) $runsSql .= ' ORDER by timestamp DESC'; $runsStmt = $this->dbcon->prepare($runsSql); @@ -27,4 +25,12 @@ class Run extends Repository $runs = $runsRslt->fetchAllAssociative(); return $runs; } + + public function addRun(int $jobid, string $exitcode, int $starttime, float $runtime, string $output, array $flags): void + { + // handling of response + $addRunSql = 'INSERT INTO run(job_id, exitcode, output, runtime, timestamp,flags) VALUES (:job_id, :exitcode, :output, :runtime, :timestamp, :flags)'; + $addRunStmt = $this->dbcon->prepare($addRunSql); + $addRunStmt->executeQuery([':job_id' => $jobid, ':exitcode' => $exitcode, 'output' => $output, 'runtime' => $runtime, ':timestamp' => $starttime, ':flags' => implode("", $flags)]); + } } \ No newline at end of file diff --git a/storage/database.sql b/storage/database.sql index 595db9b..789ed54 100644 --- a/storage/database.sql +++ b/storage/database.sql @@ -24,5 +24,6 @@ CREATE TABLE run ( exitcode TEXT NOT NULL, output TEXT NOT NULL, runtime REAL NOT NULL, - timestamp INTEGER NOT NULL + timestamp INTEGER NOT NULL, + flags TEXT NOT NULL ); \ No newline at end of file diff --git a/templates/job/view.html.twig b/templates/job/view.html.twig index dc8d050..d2da087 100644 --- a/templates/job/view.html.twig +++ b/templates/job/view.html.twig @@ -17,6 +17,9 @@
{{ run.timestamp | date("d/m/Y H:i:s") }}
(runtime: {{ run.runtime | format_number({fraction_digit: 3}) }})
+ {% if 'M' in run.flags %} +
Manual Run
+ {% endif %}
{{ run.exitcode }}