Commit 73574390 authored by Marcin Haba's avatar Marcin Haba
Browse files

baculum: Add new filters to object category sum endpoint

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
parent efa85058
......@@ -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);
}
}
......@@ -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;
}
}
}
......@@ -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/" />
......
......@@ -2239,7 +2239,7 @@
]
}
},
"/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.",
......@@ -6781,16 +6781,74 @@
"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"
}
......
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