]> git.ipfire.org Git - thirdparty/bacula.git/commitdiff
baculum: Add sources endpoint
authorMarcin Haba <marcin.haba@bacula.pl>
Thu, 1 Dec 2022 13:43:24 +0000 (14:43 +0100)
committerMarcin Haba <marcin.haba@bacula.pl>
Mon, 9 Jan 2023 12:34:42 +0000 (13:34 +0100)
gui/baculum/protected/API/Modules/Database.php
gui/baculum/protected/API/Modules/SourceManager.php [new file with mode: 0644]
gui/baculum/protected/API/Modules/SourceRecord.php [new file with mode: 0644]
gui/baculum/protected/API/Pages/API/Sources.php [new file with mode: 0644]
gui/baculum/protected/API/Pages/API/config.xml
gui/baculum/protected/API/Pages/API/endpoints.xml
gui/baculum/protected/API/openapi_baculum.json
gui/baculum/protected/Common/Modules/Errors/SourceError.php [new file with mode: 0644]

index fc80a97524e00cf80f93f2b8fac17d6725e01766..a94248dccc4849fb1041f32a39f0f3b7416fdfd9 100644 (file)
@@ -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'];
diff --git a/gui/baculum/protected/API/Modules/SourceManager.php b/gui/baculum/protected/API/Modules/SourceManager.php
new file mode 100644 (file)
index 0000000..b1d0239
--- /dev/null
@@ -0,0 +1,81 @@
+<?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);
+       }
+}
+?>
diff --git a/gui/baculum/protected/API/Modules/SourceRecord.php b/gui/baculum/protected/API/Modules/SourceRecord.php
new file mode 100644 (file)
index 0000000..0bb3c37
--- /dev/null
@@ -0,0 +1,46 @@
+<?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);
+       }
+}
diff --git a/gui/baculum/protected/API/Pages/API/Sources.php b/gui/baculum/protected/API/Pages/API/Sources.php
new file mode 100644 (file)
index 0000000..4504698
--- /dev/null
@@ -0,0 +1,104 @@
+<?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;
+       }
+}
+?>
index 56e6ccd5ea33395d62a4c81d021a87f6b0c4d6b6..bc367f08031a0b0e5dbd27fd41b1b96baa833281 100644 (file)
@@ -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" />
index ae505ad032e9882aa93763d8498badc48c241fe1..9cce05234dc4e1e7558dab9a8fe0f93ebdae6a08 100644 (file)
        <!-- 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 -->
index e31e84ec7aaa7ae18563e590e15817ec99412f39..90ebede5e16b83cc9ea53140dcb71901dfb93272 100644 (file)
                        "Object": {
                                "$ref": "#/definitions/Object"
                        },
+                       "Sources": {
+                               "type": "array",
+                               "items": {
+                                       "$ref": "#/definitions/Source"
+                               }
+                       },
+                       "Source": {
+                               "$ref": "#/definitions/Source"
+                       },
                        "Events": {
                                "type": "array",
                                "items": {
                                ]
                        }
                },
+               "/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"],
                                }
                        }
                },
+               "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": {
diff --git a/gui/baculum/protected/Common/Modules/Errors/SourceError.php b/gui/baculum/protected/Common/Modules/Errors/SourceError.php
new file mode 100644 (file)
index 0000000..779b8be
--- /dev/null
@@ -0,0 +1,33 @@
+<?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 {
+}