Commit 970ad4ff authored by Marcin Haba's avatar Marcin Haba
Browse files

baculum: Add sources endpoint

parent ebf27438
......@@ -191,6 +191,9 @@ class Database extends APIModule {
$cond[] = "{$key} {$value[$i]['operator']} :{$kval}{$i}";
$vals[":{$kval}{$i}"] = $value[$i]['vals'];
$value[$i]['operator'] = '';
} elseif (in_array($value[$i]['operator'], ['IS', 'IS NOT'])) {
$cond[] = "{$key} {$value[$i]['operator']} {$value[$i]['vals']}";
$value[$i]['operator'] = '';
} else {
$cond[] = "$key = :{$kval}{$i}";
$vals[":{$kval}{$i}"] = $value[$i]['vals'];
......
<?php
/*
* Bacula(R) - The Network Backup Solution
* Baculum - Bacula web interface
*
* Copyright (C) 2013-2022 Kern Sibbald
*
* The main author of Baculum is Marcin Haba.
* The original author of Bacula is Kern Sibbald, with contributions
* from many others, a complete list can be found in the file AUTHORS.
*
* You may use this file and others of this release according to the
* license defined in the LICENSE file, which includes the Affero General
* Public License, v3.0 ("AGPLv3") and some additional permissions and
* terms pursuant to its AGPLv3 Section 7.
*
* This notice must be preserved when any source code is
* conveyed and/or propagated.
*
* Bacula(R) is a registered trademark of Kern Sibbald.
*/
namespace Baculum\API\Modules;
/**
* Source (client + fileset + job) manager module.
*
* @author Marcin Haba <marcin.haba@bacula.pl>
* @category Module
* @package Baculum API
*/
class SourceManager extends APIModule {
public function getSources($criteria = [], $limit_val = null) {
$limit = '';
if(is_int($limit_val) && $limit_val > 0) {
$limit = ' LIMIT ' . $limit_val;
}
$where = Database::getWhere($criteria, true);
$sql = 'SELECT
sres.fileset, sres.client, sres.job, ores.starttime, ores.jobid, jres.jobstatus
FROM Job AS jres,
(
SELECT DISTINCT
FileSet.FileSet AS fileset,
Client.Name AS client,
Job.Name AS job
FROM Job
JOIN FileSet USING (FileSetId)
JOIN Client USING (ClientId)
) AS sres, (
SELECT
MAX(StartTime) AS starttime,
MAX(JobId) AS jobid,
FileSet.FileSet AS fileset,
Client.Name AS client,
Job.Name AS job
FROM Job
JOIN FileSet USING (FileSetId)
JOIN Client USING (ClientId)
GROUP BY FileSet.FileSet, Client.Name, Job.Name
) AS ores
LEFT JOIN Object USING (JobId)
WHERE
jres.JobId = ores.jobid
AND sres.job = ores.job
AND sres.client = ores.client
AND sres.fileset = ores.fileset
AND jres.Type = \'B\'
' . (!empty($where['where']) ? ' AND ' . $where['where'] : '') . '
ORDER BY sres.fileset ASC, sres.client ASC, sres.job ASC, ores.starttime ASC ' . $limit;
$connection = SourceRecord::finder()->getDbConnection();
$connection->setActive(true);
$pdo = $connection->getPdoInstance();
$sth = $pdo->prepare($sql);
$sth->execute($where['params']);
return $sth->fetchAll(\PDO::FETCH_ASSOC);
}
}
?>
<?php
/*
* Bacula(R) - The Network Backup Solution
* Baculum - Bacula web interface
*
* Copyright (C) 2013-2022 Kern Sibbald
*
* The main author of Baculum is Marcin Haba.
* The original author of Bacula is Kern Sibbald, with contributions
* from many others, a complete list can be found in the file AUTHORS.
*
* You may use this file and others of this release according to the
* license defined in the LICENSE file, which includes the Affero General
* Public License, v3.0 ("AGPLv3") and some additional permissions and
* terms pursuant to its AGPLv3 Section 7.
*
* This notice must be preserved when any source code is
* conveyed and/or propagated.
*
* Bacula(R) is a registered trademark of Kern Sibbald.
*/
namespace Baculum\API\Modules;
/**
* Source (job + client + fileset) record module.
*
* @author Marcin Haba <marcin.haba@bacula.pl>
* @category Database
* @package Baculum API
*/
class SourceRecord extends APIDbModule {
const TABLE = 'Job';
public $fileset;
public $client;
public $job;
public $endtime;
public $jobid;
public $jobstatus;
public static function finder($className = __CLASS__) {
return parent::finder($className);
}
}
<?php
/*
* Bacula(R) - The Network Backup Solution
* Baculum - Bacula web interface
*
* Copyright (C) 2013-2022 Kern Sibbald
*
* The main author of Baculum is Marcin Haba.
* The original author of Bacula is Kern Sibbald, with contributions
* from many others, a complete list can be found in the file AUTHORS.
*
* You may use this file and others of this release according to the
* license defined in the LICENSE file, which includes the Affero General
* Public License, v3.0 ("AGPLv3") and some additional permissions and
* terms pursuant to its AGPLv3 Section 7.
*
* This notice must be preserved when any source code is
* conveyed and/or propagated.
*
* Bacula(R) is a registered trademark of Kern Sibbald.
*/
use Baculum\API\Modules\BaculumAPIServer;
use Baculum\Common\Modules\Errors\SourceError;
/**
* Sources endpoint.
*
* @author Marcin Haba <marcin.haba@bacula.pl>
* @category API
* @package Baculum API
*/
class Sources extends BaculumAPIServer {
public function get() {
$misc = $this->getModule('misc');
$limit = $this->Request->contains('limit') ? (int)$this->Request['limit'] : 0;
$job = $this->Request->contains('job') && $misc->isValidName($this->Request['job']) ? $this->Request['job'] : '';
$client = $this->Request->contains('client') && $misc->isValidName($this->Request['client']) ? $this->Request['client'] : '';
$fileset = $this->Request->contains('fileset') && $misc->isValidName($this->Request['fileset']) ? $this->Request['fileset'] : '';
$starttime_from = $this->Request->contains('starttime_from') && $misc->isValidInteger($this->Request['starttime_from']) ? (int)$this->Request['starttime_from'] : null;
$starttime_to = $this->Request->contains('starttime_to') && $misc->isValidInteger($this->Request['starttime_to']) ? (int)$this->Request['starttime_to'] : null;
$jobstatus = $this->Request->contains('jobstatus') && $misc->isValidState($this->Request['jobstatus']) ? $this->Request['jobstatus'] : '';
$hasobject = $this->Request->contains('hasobject') && $misc->isValidBoolean($this->Request['hasobject']) ? $this->Request['hasobject'] : null;
// @TODO: Fix using sres and jres in this place. It can lead to a problem when sres or jres will be changed in manager.
$params = [];
if (!empty($job)) {
$params['sres.job'] = [[
'vals' => $job
]];
}
if (!empty($client)) {
$params['sres.client'] = [[
'vals' => $client
]];
}
if (!empty($fileset)) {
$params['sres.fileset'] = [[
'vals' => $fileset
]];
}
if (!empty($jobstatus)) {
$params['jres.jobstatus'] = [[
'vals' => $jobstatus
]];
}
if (!is_null($hasobject)) {
if ($misc->isValidBooleanTrue($hasobject)) {
$params['Object.ObjectId'][] = [
'operator' => 'IS NOT',
'vals' => 'NULL'
];
} elseif ($misc->isValidBooleanFalse($hasobject)) {
$params['Object.ObjectId'][] = [
'operator' => 'IS',
'vals' => 'NULL'
];
}
}
// Start time range
if (!empty($starttime_from) || !empty($starttime_to)) {
$params['ores.starttime'] = [];
if (!empty($starttime_from)) {
$params['ores.starttime'][] = [
'operator' => '>=',
'vals' => date('Y-m-d H:i:s', $starttime_from)
];
}
if (!empty($starttime_to)) {
$params['ores.starttime'][] = [
'operator' => '<=',
'vals' => date('Y-m-d H:i:s', $starttime_to)
];
}
}
$sources = $this->getModule('source')->getSources($params, $limit);
$this->output = $sources;
$this->error = SourceError::ERROR_NO_ERRORS;
}
}
?>
......@@ -30,6 +30,7 @@
<module id="volume" class="Baculum\API\Modules\VolumeManager" />
<module id="object" class="Baculum\API\Modules\ObjectManager" />
<module id="event" class="Baculum\API\Modules\EventManager" />
<module id="source" class="Baculum\API\Modules\SourceManager" />
<!-- tools modules -->
<module id="bconsole" class="Baculum\API\Modules\Bconsole" />
<module id="json_tools" class="Baculum\API\Modules\JSONTools" />
......
......@@ -100,6 +100,8 @@
<!-- event endpoints -->
<url ServiceParameter="Events" pattern="api/v2/events/" />
<url ServiceParameter="Event" pattern="api/v2/events/{id}" parameters.id="\d+" />
<!-- source endpoints -->
<url ServiceParameter="Sources" pattern="api/v2/sources/" />
<!-- @TODO: Separate this endpoint outside 'joblog' -->
<url ServiceParameter="Messages" pattern="api/v2/joblog/messages" />
<!-- fileset endpoints -->
......
......@@ -132,6 +132,15 @@
"Object": {
"$ref": "#/definitions/Object"
},
"Sources": {
"type": "array",
"items": {
"$ref": "#/definitions/Source"
}
},
"Source": {
"$ref": "#/definitions/Source"
},
"Events": {
"type": "array",
"items": {
......@@ -6782,6 +6791,104 @@
]
}
},
"/api/v2/sources": {
"get": {
"tags": ["sources"],
"summary": "Source list",
"description": "Get source list.",
"responses": {
"200": {
"description": "List of sources",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"output": {
"$ref": "#/components/schemas/Sources"
},
"error": {
"type": "integer",
"description": "Error code",
"enum": [0, 1, 2, 3, 6, 7, 1000]
}
}
}
}
}
}
},
"parameters": [
{
"$ref": "#/components/parameters/Limit"
},
{
"name": "job",
"in": "query",
"required": false,
"description": "Job name filter",
"schema": {
"type": "string"
}
},
{
"name": "client",
"in": "query",
"required": false,
"description": "Client name filter",
"schema": {
"type": "string"
}
},
{
"name": "fileset",
"in": "query",
"required": false,
"description": "Fileset name filter",
"schema": {
"type": "string"
}
},
{
"name": "starttime_from",
"in": "query",
"required": false,
"description": "Start time from (UNIX timestamp format, seconds)",
"schema": {
"type": "integer"
}
},
{
"name": "starttime_to",
"in": "query",
"required": false,
"description": "Start time to (UNIX timestamp format, seconds)",
"schema": {
"type": "integer"
}
},
{
"name": "jobstatus",
"in": "query",
"required": false,
"description": "Job status letter",
"schema": {
"type": "string",
"enum": ["C", "R", "B", "T", "W", "E", "e", "f", "D", "A", "I", "F", "S", "m", "M", "s", "j", "c", "d", "t", "p", "i", "a", "l", "L"]
}
},
{
"name": "hasobject",
"in": "query",
"required": false,
"description": "Show sources that have object, 1 - show sources with objects created, 0 - show sources without objects created",
"schema": {
"type": "boolean"
}
}
]
}
},
"/api/v2/events": {
"get": {
"tags": ["events"],
......@@ -8209,6 +8316,35 @@
}
}
},
"Source": {
"type": "object",
"properties": {
"fileset": {
"description": "Fileset name",
"type": "string"
},
"client": {
"description": "Client name",
"type": "string"
},
"job": {
"description": "Job name",
"type": "string"
},
"starttime": {
"description": "Start time latest job using this source",
"type": "string"
},
"jobid": {
"description": "Latest jobid",
"type": "integer"
},
"jobstatus": {
"description": "Job status latest job",
"type": "string"
}
}
},
"Event": {
"type": "object",
"properties": {
......
<?php
/*
* Bacula(R) - The Network Backup Solution
* Baculum - Bacula web interface
*
* Copyright (C) 2013-2022 Kern Sibbald
*
* The main author of Baculum is Marcin Haba.
* The original author of Bacula is Kern Sibbald, with contributions
* from many others, a complete list can be found in the file AUTHORS.
*
* You may use this file and others of this release according to the
* license defined in the LICENSE file, which includes the Affero General
* Public License, v3.0 ("AGPLv3") and some additional permissions and
* terms pursuant to its AGPLv3 Section 7.
*
* This notice must be preserved when any source code is
* conveyed and/or propagated.
*
* Bacula(R) is a registered trademark of Kern Sibbald.
*/
namespace Baculum\Common\Modules\Errors;
/**
* Source error class.
*
* @author Marcin Haba <marcin.haba@bacula.pl>
* @category Errors
* @package Baculum Common
*/
class SourceError extends GenericError {
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment