]> git.ipfire.org Git - thirdparty/bacula.git/commitdiff
baculum: Add new filters to object category sum endpoint
authorMarcin Haba <marcin.haba@bacula.pl>
Tue, 6 Dec 2022 10:50:14 +0000 (11:50 +0100)
committerMarcin Haba <marcin.haba@bacula.pl>
Mon, 9 Jan 2023 12:34:42 +0000 (13:34 +0100)
Changes:
 - add new filters
 - rework /objects/stats/category-sum endpoint with keeping compatibility
 - change /jobs/stats/sum filter into /jobs/stats/type-sum
 - datestart and dateend parameters are now deprecated
 - datestart does not have default value (previously 1 month)
 - update documentation

gui/baculum/protected/API/Modules/ObjectManager.php
gui/baculum/protected/API/Pages/API/ObjectStatsCategorySum.php
gui/baculum/protected/API/Pages/API/endpoints.xml
gui/baculum/protected/API/openapi_baculum.json

index 39043bbcbd82890377aab7d1319116aa35c04fed..4d9dda06d1823f8136967d4f34fd3e1c96571b00 100644 (file)
@@ -87,66 +87,6 @@ LEFT JOIN Job USING (JobId) '
                return $obj;
        }
 
-       /**
-        * Get number object per object category.
-        *
-        * @param string $objecttype object type (usually short name such as 'm365' or 'MySQL')
-        * @param string $objectsource object source
-        * @param string $datestart start date
-        * @param string $dateend end date
-        * @return array summary in form [objectcategory => '', objecttype => '', objectsource => '', count => 0, last_job_time => '']
-        */
-       public function getObjectCategorySum($objecttype = null, $objectsource = null, $datestart = null, $dateend = null) {
-               $otype = '';
-               if (!is_null($objecttype)) {
-                       $otype = ' AND oobj.ObjectType=:objecttype ';
-
-               }
-               $osource = '';
-               if (!is_null($objectsource)) {
-                       $osource = ' AND oobj.ObjectSource=:objectsource ';
-               }
-               $dformat = 'Y-m-d H:i:s';
-               if (is_null($datestart)) {
-                       $m_ago = new \DateTime('1 month ago');
-                       $datestart = $m_ago->format($dformat);
-               }
-               if (is_null($dateend)) {
-                       $dateend = date($dformat);
-               }
-
-               $sql = 'SELECT oobj.ObjectCategory AS objectcategory,
-                               oobj.ObjectType AS objecttype,
-                               oobj.ObjectSource AS objectsource,
-                               COUNT(DISTINCT oobj.ObjectUUID) AS count,
-                               MAX(Job.StartTime) AS last_job_time
-                       FROM Object AS oobj
-                       JOIN Job USING(JobId)
-                       WHERE
-                               Job.StartTime BETWEEN :datestart AND :dateend
-                               AND Job.JobStatus IN (\'T\', \'W\')
-                               AND oobj.JobId=(
-                                       SELECT MAX(iobj.JobId) FROM Object AS iobj WHERE iobj.ObjectId=oobj.ObjectId
-                               )
-                               ' . $otype . $osource . '
-                       GROUP BY oobj.ObjectCategory, oobj.ObjectType, oobj.ObjectSource';
-
-               $connection = ObjectRecord::finder()->getDbConnection();
-               $connection->setActive(true);
-               $pdo = $connection->getPdoInstance();
-               $sth = $pdo->prepare($sql);
-               if (!is_null($objecttype)) {
-                       $sth->bindParam(':objecttype', $objecttype, \PDO::PARAM_STR, 100);
-               }
-               if (!is_null($objectsource)) {
-                       $sth->bindParam(':objectsource', $objectsource, \PDO::PARAM_STR, 400);
-               }
-               $sth->bindParam(':datestart', $datestart, \PDO::PARAM_STR, 19);
-               $sth->bindParam(':dateend', $dateend, \PDO::PARAM_STR, 19);
-               $sth->execute();
-               return $sth->fetchAll(\PDO::FETCH_ASSOC);
-       }
-
        /**
         * Get object size statistics.
         *
@@ -301,4 +241,36 @@ LEFT JOIN Job USING (JobId) '
                $sth->execute();
                return $sth->fetchAll(\PDO::FETCH_ASSOC);
        }
+
+       /**
+        * Get total number of objects per object category.
+        *
+        * @param array $criteria SQL query criteria
+        * @return array object totals
+        */
+       public function getObjectCategorySum($criteria) {
+               $where = Database::getWhere($criteria);
+               $wh = !empty($where['where']) ? $where['where'] : '';
+
+               $sql = 'SELECT
+                       oobj.ObjectCategory AS objectcategory,
+                       oobj.ObjectType     AS objecttype,
+                       oobj.ObjectSource   AS objectsource,
+                       SUM(1)              AS count,
+                       MAX(Job.StartTime)  AS last_job_time
+               FROM Object AS oobj
+               JOIN Job USING(JobId)
+                       ' . ($wh ? $wh . ' AND ' : ' WHERE ') . '
+                       oobj.JobId=(
+                               SELECT MAX(iobj.JobId) FROM Object AS iobj WHERE iobj.ObjectId=oobj.ObjectId
+                       )
+               GROUP BY objectcategory, objecttype, objectsource';
+
+               $connection = ObjectRecord::finder()->getDbConnection();
+               $connection->setActive(true);
+               $pdo = $connection->getPdoInstance();
+               $sth = $pdo->prepare($sql);
+               $sth->execute($where['params']);
+               return $sth->fetchAll(\PDO::FETCH_ASSOC);
+       }
 }
index 66aa34fa25801721260dc89280c7d6f3de23e062..f32c5524255e2a121ee14a4204ec5ed8b147721c 100644 (file)
@@ -21,6 +21,7 @@
  */
 
 use Baculum\Common\Modules\Errors\ObjectError;
+use Baculum\Common\Modules\Errors\JobError;
 
 /**
  * Object category stats endpoint.
@@ -41,6 +42,7 @@ class ObjectStatsCategorySum extends BaculumAPIServer {
                if ($this->Request->contains('objectsource') && $misc->isValidName($this->Request['objectsource'])) {
                        $objectsource = $this->Request['objectsource'];
                }
+               // TODO: Remove datestart/dateend filters since they are not compatible with rest of the API
                $datestart = null;
                if ($this->Request->contains('datestart') && $misc->isValidBDateAndTime($this->Request['datestart'])) {
                        $datestart = $this->Request['datestart'];
@@ -50,13 +52,154 @@ class ObjectStatsCategorySum extends BaculumAPIServer {
                        $dateend = $this->Request['dateend'];
                }
 
-               $objects = $this->getModule('object')->getObjectCategorySum(
-                       $objecttype,
-                       $objectsource,
-                       $datestart,
-                       $dateend
+               $jobstatus = $this->Request->contains('jobstatus') && $this->Request['jobstatus'] ? $this->Request['jobstatus'] : '';
+               $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;
+               $jobname = $this->Request->contains('jobname') && $misc->isValidName($this->Request['jobname']) ? $this->Request['jobname'] : '';
+               $clientid = $this->Request->contains('clientid') ? $this->Request['clientid'] : '';
+
+               if (!empty($clientid) && !$misc->isValidId($clientid)) {
+                       $this->output = JobError::MSG_ERROR_CLIENT_DOES_NOT_EXISTS;
+                       $this->error = JobError::ERROR_CLIENT_DOES_NOT_EXISTS;
+                       return;
+               }
+               $client = $this->Request->contains('client') ? $this->Request['client'] : '';
+               if (!empty($client) && !$misc->isValidName($client)) {
+                       $this->output = JobError::MSG_ERROR_CLIENT_DOES_NOT_EXISTS;
+                       $this->error = JobError::ERROR_CLIENT_DOES_NOT_EXISTS;
+                       return;
+               }
+
+               $params = [];
+
+               if (!empty($objecttype)) {
+                       $params['oobj.ObjectType'] = [];
+                       $params['oobj.ObjectType'][] = [
+                               'vals' => $objecttype
+                       ];
+               }
+
+               if (!empty($objectsource)) {
+                       $params['oobj.ObjectSource'] = [];
+                       $params['oobj.ObjectSource'][] = [
+                               'vals' => $objectsource
+                       ];
+               }
+
+               $result = $this->getModule('bconsole')->bconsoleCommand(
+                       $this->director,
+                       ['.jobs'],
+                       null,
+                       true
                );
-               $this->output = $objects;
-               $this->error = ObjectError::ERROR_NO_ERRORS;
+               if ($result->exitcode === 0) {
+                       $vals = [];
+                       if (!empty($jobname)) {
+                               if (in_array($jobname, $result->output)) {
+                                       $vals = [$jobname];
+                               }
+                       } else {
+                               $vals = $result->output;
+                       }
+                       if (count($vals) == 0) {
+                               // no $vals criteria means that user has no job resource assigned.
+                               $this->output = [];
+                               $this->error = JobError::ERROR_NO_ERRORS;
+                               return;
+                       }
+
+                       $params['Job.Name'] = [];
+                       $params['Job.Name'][] = [
+                               'operator' => 'OR',
+                               'vals' => $vals
+                       ];
+               }
+
+               $error = false;
+               // Client name and clientid filter
+               if (!empty($client) || !empty($clientid)) {
+                       $result = $this->getModule('bconsole')->bconsoleCommand(
+                               $this->director,
+                               ['.client']
+                       );
+                       if ($result->exitcode === 0) {
+                               array_shift($result->output);
+                               $cli = null;
+                               if (!empty($client)) {
+                                       $cli = $this->getModule('client')->getClientByName($client);
+                               } elseif (!empty($clientid)) {
+                                       $cli = $this->getModule('client')->getClientById($clientid);
+                               }
+                               if (is_object($cli) && in_array($cli->name, $result->output)) {
+                                       $params['Job.ClientId'] = [];
+                                       $params['Job.ClientId'][] = [
+                                               'operator' => 'AND',
+                                               'vals' => [$cli->clientid]
+                                       ];
+                               } else {
+                                       $error = true;
+                                       $this->output = JobError::MSG_ERROR_CLIENT_DOES_NOT_EXISTS;
+                                       $this->error = JobError::ERROR_CLIENT_DOES_NOT_EXISTS;
+                               }
+                       } else {
+                               $error = true;
+                               $this->output = $result->output;
+                               $this->error = $result->exitcode;
+                       }
+               }
+
+               $jobstatuses = array_keys($misc->getJobState());
+               $sts = str_split($jobstatus);
+               for ($i = 0; $i < count($sts); $i++) {
+                       if (in_array($sts[$i], $jobstatuses)) {
+                               if (!key_exists('Job.JobStatus', $params)) {
+                                       $params['Job.JobStatus'] = [[
+                                               'operator' => 'OR',
+                                               'vals' => []
+                                       ]];
+                               }
+                               $params['Job.JobStatus'][0]['vals'][] = $sts[$i];
+                       }
+               }
+
+               // Start time range
+               if (!empty($starttime_from) || !empty($datestart) || !empty($starttime_to) || !empty($dateend)) {
+                       $params['Job.StartTime'] = [];
+                       $start = null;
+                       if (!empty($starttime_from)) {
+                               $start = date('Y-m-d H:i:s', $starttime_from);
+                       } elseif (!empty($datestart)) {
+                               $start = $datestart;
+                       }
+
+                       if (!is_null($start)) {
+                               $params['Job.StartTime'][] = [
+                                       'operator' => '>=',
+                                       'vals' => $start
+                               ];
+                       }
+
+                       $end = null;
+                       if (!empty($starttime_to)) {
+                               $end = date('Y-m-d H:i:s', $starttime_to);
+                       } elseif (!empty($dateend)) {
+                               $end = $dateend;
+                       }
+
+                       if (!is_null($end)) {
+                               $params['Job.StartTime'][] = [
+                                       'operator' => '<=',
+                                       'vals' => $end
+                               ];
+                       }
+               }
+
+               if ($error === false) {
+                       $objects = $this->getModule('object')->getObjectCategorySum(
+                               $params
+                       );
+                       $this->output = $objects;
+                       $this->error = ObjectError::ERROR_NO_ERRORS;
+               }
        }
 }
index 806d0b6df511b6289baf6ffddf3ca6f526087b83..45743da41349e9dacee2fb849d3ecc73cf326273 100644 (file)
@@ -79,7 +79,7 @@
        <url ServiceParameter="RestoreRun" pattern="api/v2/jobs/restore/" />
        <url ServiceParameter="LlistPluginRestoreConf" pattern="api/v2/jobs/restore/plugin/config" />
        <url ServiceParameter="LlistPluginRestoreConfFields" pattern="api/v2/jobs/restore/plugin/config/fields" />
-       <url ServiceParameter="JobStatsJobSum" pattern="api/v2/jobs/stats/sum" />
+       <url ServiceParameter="JobStatsJobSum" pattern="api/v2/jobs/stats/type-sum/" />
        <!-- bvfs endpoints-->
        <url ServiceParameter="BVFSUpdate" pattern="api/v2/bvfs/update/" />
        <url ServiceParameter="BVFSLsDirs" pattern="api/v2/bvfs/lsdirs/" />
index 5dc391b7f83406eccc49780604fd6f6d2fbbd29f..c3cf91599b67666bcbd3b83921f1533d265cc90d 100644 (file)
                                ]
                        }
                },
-               "/api/v2/jobs/stats/sum": {
+               "/api/v2/jobs/stats/type-sum": {
                        "get": {
                                "tags": ["jobs"],
                                "summary": "Total number of jobs with specific job type and job status.",
                                                "name": "datestart",
                                                "in": "query",
                                                "required": false,
-                                               "description": "Start date for job time range. If not given, default is used 1 month ago date.",
+                                               "description": "Start date for job time range in form YYYY-MM-DD HH:II:SS.",
                                                "schema": {
                                                        "type": "string"
-                                               }
+                                               },
+                                               "deprecated": true
                                        },
                                        {
                                                "name": "dateend",
                                                "in": "query",
                                                "required": false,
-                                               "description": "End date for job time range. If not given, default is used current date.",
+                                               "description": "End date for job time range in form YYYY-MM-DD HH:II:SS.",
+                                               "schema": {
+                                                       "type": "string"
+                                               },
+                                               "deprecated": true
+                                       },
+                                       {
+                                               "name": "jobstatus",
+                                               "in": "query",
+                                               "description": "Job status letter(s). Possible multiple values like 'Ef' or 'Tef'",
+                                               "required": false,
+                                               "schema": {
+                                                       "type": "string",
+                                                       "description": "Job status. Note, some statuses can be not visible outside (used internally by Bacula)",
+                                                       "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": "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": "jobname",
+                                               "in": "query",
+                                               "description": "Job name",
+                                               "required": false,
+                                               "schema": {
+                                                       "type": "string"
+                                               }
+                                       },
+                                       {
+                                               "name": "clientid",
+                                               "in": "query",
+                                               "description": "Client identifier (can be used instead of client value)",
+                                               "required": false,
+                                               "schema": {
+                                                       "type": "integer"
+                                               }
+                                       },
+                                       {
+                                               "name": "client",
+                                               "in": "query",
+                                               "description": "Client name (can be used instead clientid)",
+                                               "required": false,
                                                "schema": {
                                                        "type": "string"
                                                }