From: Marcin Haba Date: Sun, 1 Dec 2019 13:22:43 +0000 (+0100) Subject: baculum: Add API changes to support restore from copy jobs X-Git-Tag: Release-9.6.0~62 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ab723769c953c00fc67cf1e971d0a08b8b58fd61;p=thirdparty%2Fbacula.git baculum: Add API changes to support restore from copy jobs --- diff --git a/gui/baculum/protected/API/Class/JobManager.php b/gui/baculum/protected/API/Class/JobManager.php index bd645342d..aee274213 100644 --- a/gui/baculum/protected/API/Class/JobManager.php +++ b/gui/baculum/protected/API/Class/JobManager.php @@ -3,7 +3,7 @@ * Bacula(R) - The Network Backup Solution * Baculum - Bacula web interface * - * Copyright (C) 2013-2018 Kern Sibbald + * Copyright (C) 2013-2019 Kern Sibbald * * The main author of Baculum is Marcin Haba. * The original author of Bacula is Kern Sibbald, with contributions @@ -74,32 +74,101 @@ class JobManager extends APIModule { return JobRecord::finder()->deleteByjobid($id); } - public function getRecentJobids($jobname, $clientid, $filesetid) { - $sql = "name='$jobname' AND clientid='$clientid' AND filesetid='$filesetid' AND jobstatus IN ('T', 'W') AND level IN ('F', 'I', 'D')"; + /** + * Find all compojobs required to do full restore. + * + * @param array $jobs jobid to start searching for jobs + * @return array compositional jobs regarding given jobid + */ + private function findCompositionalJobs(array $jobs) { + $jobids = []; + $wait_on_full = false; + foreach($jobs as $job) { + if($job->level == 'F') { + $jobids[] = $job->jobid; + break; + } elseif($job->level == 'D' && $wait_on_full === false) { + $jobids[] = $job->jobid; + $wait_on_full = true; + } elseif($job->level == 'I' && $wait_on_full === false) { + $jobids[] = $job->jobid; + } + } + return $jobids; + } + + /** + * Get latest recent compositional jobids to do restore. + * + * @param string $jobname job name + * @param integer $clientid client identifier + * @param integer $filesetid fileset identifier + * @param boolean $inc_copy_job determine if include copy jobs to result + * @return array list of jobids required to do restore + */ + public function getRecentJobids($jobname, $clientid, $filesetid, $inc_copy_job = false) { + $types = "('B')"; + if ($inc_copy_job) { + $types = "('B', 'C')"; + } + $sql = "name='$jobname' AND clientid='$clientid' AND filesetid='$filesetid' AND type IN $types AND jobstatus IN ('T', 'W') AND level IN ('F', 'I', 'D')"; $finder = JobRecord::finder(); $criteria = new TActiveRecordCriteria; - $order = 'EndTime'; + $order1 = 'RealEndTime'; + $order2 = 'JobId'; $db_params = $this->getModule('api_config')->getConfig('db'); if ($db_params['type'] === Database::PGSQL_TYPE) { - $order = strtolower($order); + $order1 = strtolower($order1); + $order2 = strtolower($order2); } - $criteria->OrdersBy[$order] = 'desc'; + $criteria->OrdersBy[$order1] = 'desc'; + $criteria->OrdersBy[$order2] = 'desc'; $criteria->Condition = $sql; $jobs = $finder->findAll($criteria); $jobids = array(); - $waitForFull = false; - if(!is_null($jobs)) { - foreach($jobs as $job) { - if($job->level == 'F') { - $jobids[] = $job->jobid; - break; - } elseif($job->level == 'D' && $waitForFull === false) { - $jobids[] = $job->jobid; - $waitForFull = true; - } elseif($job->level == 'I' && $waitForFull === false) { - $jobids[] = $job->jobid; + if(is_array($jobs)) { + $jobids = $this->findCompositionalJobs($jobs); + } + return $jobids; + } + + /** + * Get compositional jobids to do restore starting from given job (full/incremental/differential). + * + * @param integer $jobid job identifier of last job to do restore + * @return array list of jobids required to do restore + */ + public function getJobidsToRestore($jobid) { + $jobids = []; + $bjob = JobRecord::finder()->findBySql( + "SELECT * FROM job WHERE jobid = '$jobid' AND jobstatus IN ('T', 'W') AND type IN ('B', 'C') AND level IN ('F', 'I', 'D')" + ); + if (is_object($bjob)) { + if ($bjob->level != 'F') { + $sql = "clientid=:clientid AND filesetid=:filesetid AND type IN ('B', 'C')" . + " AND jobstatus IN ('T', 'W') AND level IN ('F', 'I', 'D') " . + " AND starttime <= :starttime and jobid <= :jobid"; + $finder = JobRecord::finder(); + $criteria = new TActiveRecordCriteria; + $order1 = 'JobId'; + $db_params = $this->getModule('api_config')->getConfig('db'); + if ($db_params['type'] === Database::PGSQL_TYPE) { + $order1 = strtolower($order1); + } + $criteria->OrdersBy[$order1] = 'desc'; + $criteria->Condition = $sql; + $criteria->Parameters[':clientid'] = $bjob->clientid; + $criteria->Parameters[':filesetid'] = $bjob->filesetid; + $criteria->Parameters[':starttime'] = $bjob->endtime; + $criteria->Parameters[':jobid'] = $bjob->jobid; + $jobs = $finder->findAll($criteria); + + if(is_array($jobs)) { + $jobids = $this->findCompositionalJobs($jobs); } + } else { + $jobids[] = $bjob->jobid; } } return $jobids; diff --git a/gui/baculum/protected/API/Pages/API/BVFSGetJobids.php b/gui/baculum/protected/API/Pages/API/BVFSGetJobids.php index 970dcd90e..30ab404df 100644 --- a/gui/baculum/protected/API/Pages/API/BVFSGetJobids.php +++ b/gui/baculum/protected/API/Pages/API/BVFSGetJobids.php @@ -3,7 +3,7 @@ * Bacula(R) - The Network Backup Solution * Baculum - Bacula web interface * - * Copyright (C) 2013-2018 Kern Sibbald + * Copyright (C) 2013-2019 Kern Sibbald * * The main author of Baculum is Marcin Haba. * The original author of Bacula is Kern Sibbald, with contributions @@ -24,11 +24,30 @@ class BVFSGetJobids extends BaculumAPIServer { public function get() { $jobid = $this->Request->contains('jobid') ? intval($this->Request['jobid']) : 0; + $inc_copy_job = $this->Request->contains('inc_copy_job') ? intval($this->Request['inc_copy_job']) : 0; if ($jobid > 0) { - $cmd = array('.bvfs_get_jobids', 'jobid="' . $jobid . '"'); - $result = $this->getModule('bconsole')->bconsoleCommand($this->director, $cmd); - $this->output = $result->output; - $this->error = $result->exitcode; + $result = array(); + $error = BVFSError::ERROR_NO_ERRORS; + if ($inc_copy_job == 1) { + /** + * To use copy jobs to restore here is used Baculum own method to get + * all compositional jobs. It is because of a bug in .bvfs_get_jobids command + * reported here: + * http://bugs.bacula.org/view.php?id=2500 + */ + $jobids = $this->getModule('job')->getJobidsToRestore($jobid); + $jobids_str = implode(',', $jobids); // implode to be compatible with Bvfs output + if (!empty($jobids_str)) { + $result = array($jobids_str); + } + } else { + $cmd = array('.bvfs_get_jobids', 'jobid="' . $jobid . '"'); + $jobids = $this->getModule('bconsole')->bconsoleCommand($this->director, $cmd); + $result = $jobids->output; + $error = $jobids->exitcode; + } + $this->output = $result; + $this->error = $error; } else { $this->output = BVFSError::MSG_ERROR_INVALID_JOBID; $this->error = BVFSError::ERROR_INVALID_JOBID; diff --git a/gui/baculum/protected/API/Pages/API/BVFSVersions.php b/gui/baculum/protected/API/Pages/API/BVFSVersions.php index 1d71185c1..9fd56f52e 100644 --- a/gui/baculum/protected/API/Pages/API/BVFSVersions.php +++ b/gui/baculum/protected/API/Pages/API/BVFSVersions.php @@ -3,7 +3,7 @@ * Bacula(R) - The Network Backup Solution * Baculum - Bacula web interface * - * Copyright (C) 2013-2017 Kern Sibbald + * Copyright (C) 2013-2019 Kern Sibbald * * The main author of Baculum is Marcin Haba. * The original author of Bacula is Kern Sibbald, with contributions @@ -26,6 +26,7 @@ class BVFSVersions extends BaculumAPIServer { $jobid = $this->Request->contains('jobid') ? intval($this->Request['jobid']) : 0; $pathid = $this->Request->contains('pathid') ? intval($this->Request['pathid']) : 0; $filenameid = $this->Request->contains('filenameid') ? intval($this->Request['filenameid']) : 0; + $copies = $this->Request->contains('copies') ? intval($this->Request['copies']) : 0; $client = null; if ($this->Request->contains('client') && $this->getModule('misc')->isValidName($this->Request['client'])) { $client = $this->Request['client']; @@ -44,6 +45,9 @@ class BVFSVersions extends BaculumAPIServer { 'pathid="' . $pathid . '"', 'fnid="' . $filenameid . '"' ); + if ($copies == 1) { + $cmd[] = 'copies'; + } $result = $this->getModule('bconsole')->bconsoleCommand($this->director, $cmd); $this->output = $result->output; $this->error = $result->exitcode; diff --git a/gui/baculum/protected/API/Pages/API/JobsRecent.php b/gui/baculum/protected/API/Pages/API/JobsRecent.php index f38e79a8e..332bdd73e 100644 --- a/gui/baculum/protected/API/Pages/API/JobsRecent.php +++ b/gui/baculum/protected/API/Pages/API/JobsRecent.php @@ -3,7 +3,7 @@ * Bacula(R) - The Network Backup Solution * Baculum - Bacula web interface * - * Copyright (C) 2013-2018 Kern Sibbald + * Copyright (C) 2013-2019 Kern Sibbald * * The main author of Baculum is Marcin Haba. * The original author of Bacula is Kern Sibbald, with contributions @@ -23,6 +23,7 @@ class JobsRecent extends BaculumAPIServer { public function get() { $jobname = $this->Request->contains('name') ? $this->Request['name'] : ''; + $inc_copy_job = $this->Request->contains('inc_copy_job') ? intval($this->Request['inc_copy_job']) : 0; $clientid = null; if ($this->Request->contains('clientid')) { $clientid = intval($this->Request['clientid']); @@ -55,7 +56,7 @@ class JobsRecent extends BaculumAPIServer { if ($result->exitcode === 0) { array_shift($result->output); if (in_array($jobname, $result->output)) { - $jobs = $this->getModule('job')->getRecentJobids($jobname, $clientid, $filesetid); + $jobs = $this->getModule('job')->getRecentJobids($jobname, $clientid, $filesetid, $inc_copy_job); if (is_array($jobs)) { $this->output = $jobs; $this->error = JobError::ERROR_NO_ERRORS; diff --git a/gui/baculum/protected/API/openapi_baculum.json b/gui/baculum/protected/API/openapi_baculum.json index 704cdfbe2..4fcbbcfd5 100644 --- a/gui/baculum/protected/API/openapi_baculum.json +++ b/gui/baculum/protected/API/openapi_baculum.json @@ -3660,6 +3660,16 @@ "schema": { "type": "integer" } + }, + { + "name": "copies", + "in": "query", + "description": "If set to 1, lists copy job file versions together with backup job file versions", + "required": false, + "schema": { + "type": "integer", + "default": 0 + } } ] }