Commit 9f3421aa authored by Marcin Haba's avatar Marcin Haba
Browse files

baculum: Add job sum statistics endpoint

parent 970ad4ff
......@@ -412,5 +412,24 @@ WHERE Client.ClientId='$clientid' $wh";
}
return $result;
}
public function getNumberOfJobs($criteria) {
$where = Database::getWhere($criteria);
$sql = 'SELECT
Type AS type,
SUM(1) AS total,
JobStatus AS jobstatus
FROM Job
' . (!empty($where['where']) ? $where['where'] : '') . '
GROUP BY type, jobstatus';
$connection = JobRecord::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.
*/
use Baculum\Common\Modules\Errors\JobError;
/**
* Job count stats endpoint.
*
* @author Marcin Haba <marcin.haba@bacula.pl>
* @category API
* @package Baculum API
*/
class JobStatsJobSum extends BaculumAPIServer {
public function get() {
$misc = $this->getModule('misc');
$jobstatus = $this->Request->contains('jobstatus') && $this->Request['jobstatus'] ? $this->Request['jobstatus'] : '';
$type = $this->Request->contains('type') && $misc->isValidJobType($this->Request['type']) ? $this->Request['type'] : '';
$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 = [];
$result = $this->getModule('bconsole')->bconsoleCommand(
$this->director,
['.jobs'],
null,
true
);
if ($result->exitcode === 0) {
$vals = [];
if (!empty($jobname) && 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];
}
}
if (!empty($type)) {
$params['Job.Type'] = [];
$params['Job.Type'][] = [
'vals' => $type
];
}
// Start time range
if (!empty($starttime_from) || !empty($starttime_to)) {
$params['Job.StartTime'] = [];
if (!empty($starttime_from)) {
$params['Job.StartTime'][] = [
'operator' => '>=',
'vals' => date('Y-m-d H:i:s', $starttime_from)
];
}
if (!empty($starttime_to)) {
$params['Job.StartTime'][] = [
'operator' => '<=',
'vals' => date('Y-m-d H:i:s', $starttime_to)
];
}
}
if ($error === false) {
$jobs = $this->getModule('job')->getNumberOfJobs($params);
$this->output = $jobs;
$this->error = JobError::ERROR_NO_ERRORS;
}
}
}
......@@ -79,6 +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" />
<!-- bvfs endpoints-->
<url ServiceParameter="BVFSUpdate" pattern="api/v2/bvfs/update/" />
<url ServiceParameter="BVFSLsDirs" pattern="api/v2/bvfs/lsdirs/" />
......
......@@ -2229,6 +2229,124 @@
]
}
},
"/api/v2/jobs/stats/sum": {
"get": {
"tags": ["jobs"],
"summary": "Total number of jobs with specific job type and job status.",
"consumes": [ "application/json" ],
"description": "Get total number of jobs with specific job type and job status.",
"responses": {
"200": {
"description": "Total number of jobs.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"output": {
"type": "array",
"items": {
"type": "object",
"properties": {
"type": {
"type": "string",
"description": "Job type",
"enum": ["B", "M", "V", "R", "I", "D", "A", "C", "c", "g"]
},
"total": {
"type": "integer",
"description": "Total number of the specific type jobs."
},
"jobstatus": {
"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"]
}
}
}
},
"error": {
"type": "integer",
"description": "Error code",
"enum": [0, 1, 2, 3, 4, 5, 6, 7, 10, 11, 1000]
}
}
}
}
}
}
},
"parameters": [
{
"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": "type",
"in": "query",
"description": "Job type",
"required": false,
"schema": {
"type": "string",
"description": "Job type",
"enum": ["B", "M", "V", "R", "I", "D", "A", "C", "c", "g"]
}
},
{
"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"
}
}
]
}
},
"/api/v2/storages": {
"get": {
"tags": ["storages"],
......
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