namespace Baculum\API\Modules;
+use PDO;
+
/**
* Volume manager module.
*
*/
class VolumeManager extends APIModule {
+ /**
+ * Volume types (voltype property)
+ */
+ const VOLTYPE_FILE = 1;
+ const VOLTYPE_TAPE = 2;
+ const VOLTYPE_DVD = 3;
+ const VOLTYPE_FIFO = 4;
+ const VOLTYPE_VTAPE_DEV = 5;
+ const VOLTYPE_FTP_DEV = 6;
+ const VOLTYPE_VTL_DEV = 7;
+ const VOLTYPE_ADATA = 8;
+ const VOLTYPE_ALIGNED_DEV = 9;
+ const VOLTYPE_DEDUP_OLD_DEV = 10;
+ const VOLTYPE_NULL_DEV = 11;
+ const VOLTYPE_VALIGNED_DEV = 12;
+ const VOLTYPE_VDEDUP_DEV = 13;
+ const VOLTYPE_CLOUD_DEV = 14;
+ const VOLTYPE_DEDUP_DEV = 15;
+
+ /**
+ * Get disk volume type identifiers.
+ *
+ * @return array disk volume type identifiers
+ */
+ private function getDiskVolTypes() {
+ return [
+ self::VOLTYPE_FILE,
+ self::VOLTYPE_ADATA,
+ self::VOLTYPE_FIFO,
+ self::VOLTYPE_ALIGNED_DEV,
+ self::VOLTYPE_DEDUP_OLD_DEV,
+ self::VOLTYPE_VALIGNED_DEV,
+ self::VOLTYPE_VDEDUP_DEV,
+ self::VOLTYPE_CLOUD_DEV,
+ self::VOLTYPE_DEDUP_DEV
+ ];
+ }
+
+
+ /**
+ * Get tape volume type identifiers.
+ *
+ * @return array tape volume type identifiers
+ */
+ private function getTapeVolTypes() {
+ return [
+ self::VOLTYPE_TAPE,
+ self::VOLTYPE_VTL_DEV
+ ];
+ }
+
+
+ /**
+ * Get cloud volume type identifiers.
+ *
+ * @return array cloud volume type identifiers
+ */
+ private function getCloudVolTypes() {
+ return [
+ self::VOLTYPE_CLOUD_DEV
+ ];
+ }
+
public function getVolumes($criteria = array(), $limit_val = 0, $offset_val = 0) {
$order_pool_id = 'PoolId';
$order_volume = 'VolumeName';
return $volumes;
}
+ /**
+ * Get volume overview.
+ *
+ * @param array $criteria SQL criteria to get volume overview
+ * @param integer $limit_val item limit
+ * @param integer $offset_val offset value
+ * @return array volume overview
+ */
+ public function getMediaOverview($criteria = [], $limit_val = 0, $offset_val = 0) {
+ $limit = '';
+ if(is_int($limit_val) && $limit_val > 0) {
+ $limit = " LIMIT $limit_val ";
+ }
+ $offset = '';
+ if (is_int($offset_val) && $offset_val > 0) {
+ $offset = ' OFFSET ' . $offset_val;
+ }
+
+ $where = Database::getWhere($criteria);
+
+ // get volume type count
+ $sql = 'SELECT
+ VolType AS voltype,
+ COUNT(1) AS count
+ FROM Media
+ JOIN Pool USING (PoolId)
+ ' . $where['where'] . '
+ GROUP BY VolType ';
+
+ $statement = Database::runQuery($sql, $where['params']);
+ $voltype_count = $statement->fetchAll(PDO::FETCH_ASSOC);
+
+ $expire_query = '';
+ $db_params = $this->getModule('api_config')->getConfig('db');
+ if ($db_params['type'] === Database::PGSQL_TYPE) {
+ $expire_query = 'CAST((DATE_PART(\'epoch\', Media.LastWritten) + Media.VolRetention) AS INTEGER)';
+ } elseif ($db_params['type'] === Database::MYSQL_TYPE) {
+ $expire_query = 'CAST((UNIX_TIMESTAMP(Media.LastWritten) + Media.VolRetention) AS UNSIGNED)';
+ } elseif ($db_params['type'] === Database::SQLITE_TYPE) {
+ $expire_query = 'CAST((strftime(\'%s\', Media.LastWritten) + Media.VolRetention) AS INTEGER)';
+ }
+
+ // get disk volume types (file, dedup and alighed together)
+ $vt_disk = $this->getDiskVolTypes();
+ $sql = 'SELECT
+ VolumeName AS volumename,
+ Pool.Name AS pool,
+ Storage.Name AS storage,
+ VolBytes AS volbytes,
+ VolABytes AS volabytes,
+ InChanger AS inchanger,
+ Slot AS slot,
+ CASE
+ WHEN Media.VolStatus IN (\'Full\', \'Used\') THEN ' . $expire_query . '
+ ELSE 0
+ END expiresin
+ FROM Media
+ JOIN Storage USING (StorageId)
+ JOIN Pool USING (PoolId)
+ ' . (!empty($where['where']) ? $where['where'] . ' AND ' : ' WHERE ') . ' VolType IN (' . implode(',', $vt_disk) . ')
+ ORDER BY VolStatus ASC, LastWritten DESC' . $limit . $offset;
+
+ $statement = Database::runQuery($sql, $where['params']);
+ $voltype_disk = $statement->fetchAll(PDO::FETCH_OBJ);
+
+ // get tape volume types
+ $vt_tape = $this->getTapeVolTypes();
+ $sql = 'SELECT
+ VolumeName AS volumename,
+ Pool.Name AS pool,
+ Storage.Name AS storage,
+ VolBytes AS volbytes,
+ VolABytes AS volabytes,
+ InChanger AS inchanger,
+ Slot AS slot,
+ CASE
+ WHEN Media.VolStatus IN (\'Full\', \'Used\') THEN ' . $expire_query . '
+ ELSE 0
+ END expiresin
+ FROM Media
+ JOIN Storage USING (StorageId)
+ JOIN Pool USING (PoolId)
+ ' . (!empty($where['where']) ? $where['where'] . ' AND ' : ' WHERE ') . ' VolType IN (' . implode(',', $vt_tape) . ')
+ ORDER BY VolStatus ASC, LastWritten DESC' . $limit . $offset;
+
+ $statement = Database::runQuery($sql, $where['params']);
+ $voltype_tape = $statement->fetchAll(PDO::FETCH_OBJ);
+
+ // get cloud volume types
+ $vt_cloud = $this->getCloudVolTypes();
+ $sql = 'SELECT
+ VolumeName AS volumename,
+ Pool.Name AS pool,
+ Storage.Name AS storage,
+ VolBytes AS volbytes,
+ VolABytes AS volabytes,
+ InChanger AS inchanger,
+ Slot AS slot,
+ CASE
+ WHEN Media.VolStatus IN (\'Full\', \'Used\') THEN ' . $expire_query . '
+ ELSE 0
+ END expiresin
+ FROM Media
+ JOIN Storage USING (StorageId)
+ JOIN Pool USING (PoolId)
+ ' . (!empty($where['where']) ? $where['where'] . ' AND ' : ' WHERE ') . ' VolType IN (' . implode(',', $vt_cloud) . ')
+ ORDER BY VolStatus ASC, LastWritten DESC' . $limit . $offset;
+
+ $statement = Database::runQuery($sql, $where['params']);
+ $voltype_cloud = $statement->fetchAll(PDO::FETCH_OBJ);
+
+ $disk_count = $tape_count = $cloud_count = 0;
+ for ($i = 0; $i < count($voltype_count); $i++) {
+ $count = $voltype_count[$i]['count'];
+ $voltype = $voltype_count[$i]['voltype'];
+ if (in_array($voltype, $vt_disk)) {
+ $disk_count += $count;
+ } elseif (in_array($voltype, $vt_tape)) {
+ $tape_count += $count;
+ } elseif (in_array($voltype, $vt_cloud)) {
+ $cloud_count += $count;
+ }
+ }
+
+ $result = [
+ 'disk' => [
+ 'media' => $voltype_disk,
+ 'count' => $disk_count
+ ],
+ 'tape' => [
+ 'media' => $voltype_tape,
+ 'count' => $tape_count
+ ],
+ 'cloud' => [
+ 'media' => $voltype_cloud,
+ 'count' => $cloud_count
+ ]
+ ];
+ return $result;
+ }
+
public function getVolumesByPoolId($poolid) {
$volumes = $this->getVolumes(array(
'Media.PoolId' => [[
--- /dev/null
+<?php
+/*
+ * Bacula(R) - The Network Backup Solution
+ * Baculum - Bacula web interface
+ *
+ * Copyright (C) 2013-2023 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\PoolError;
+
+/**
+ * Media/Volumes overview endpoint.
+ *
+ * @author Marcin Haba <marcin.haba@bacula.pl>
+ * @category API
+ * @package Baculum API
+ */
+class VolumesOverview extends BaculumAPIServer {
+ public function get() {
+ $misc = $this->getModule('misc');
+ $limit = $this->Request->contains('limit') ? intval($this->Request['limit']) : 0;
+ $offset = $this->Request->contains('offset') && $misc->isValidInteger($this->Request['offset']) ? (int)$this->Request['offset'] : 0;
+ $pools = $this->getModule('pool')->getPools();
+ $result = $this->getModule('bconsole')->bconsoleCommand(
+ $this->director,
+ ['.pool'],
+ null,
+ true
+ );
+ if ($result->exitcode === 0) {
+ if (is_array($pools) && count($pools) > 0) {
+ $params = [];
+ $pools_output = [];
+ foreach ($pools as $pool) {
+ if (in_array($pool->name, $result->output)) {
+ $pools_output[] = $pool->name;
+ }
+ }
+ $params['Pool.Name'] = [];
+ $params['Pool.Name'][] = [
+ 'operator' => 'IN',
+ 'vals' => $pools_output
+ ];
+ $ret = $this->getModule('volume')->getMediaOverview(
+ $params,
+ $limit,
+ $offset
+ );
+ $this->output = $ret;
+ $this->error = PoolError::ERROR_NO_ERRORS;
+ } else {
+ $this->output = PoolError::MSG_ERROR_POOL_DOES_NOT_EXISTS;
+ $this->error = PoolError::ERROR_POOL_DOES_NOT_EXISTS;
+ }
+ } else {
+ $this->output = PoolError::MSG_ERROR_WRONG_EXITCODE;
+ $this->error = PoolError::ERROR_WRONG_EXITCODE . ' Exitcode=> ' . $result->exitcode;
+ }
+ }
+}
+?>
},
"PluginM365EmailAttachment": {
"$ref": "#/definitions/PluginM365EmailAttachment"
+ },
+ "VolumeOverview": {
+ "$ref": "#/definitions/VolumeOverview"
}
},
"parameters": {
]
}
},
+ "/api/v2/volumes/overview": {
+ "get": {
+ "tags": ["volumes"],
+ "summary": "Get volumes overview.",
+ "description": "Get volumes overview.",
+ "responses": {
+ "200": {
+ "description": "Volumes overview.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "output": {
+ "type": "object",
+ "properties": {
+ "disk": {
+ "type": "object",
+ "properties": {
+ "media": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/VolumeOverview"
+ }
+ },
+ "count": {
+ "type": "integer",
+ "description": "Disk media count"
+ }
+ }
+ },
+ "tape": {
+ "type": "object",
+ "properties": {
+ "media": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/VolumeOverview"
+ }
+ },
+ "count": {
+ "type": "integer",
+ "description": "Tape media count"
+ }
+ }
+ },
+ "cloud": {
+ "type": "object",
+ "properties": {
+ "media": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/VolumeOverview"
+ }
+ },
+ "count": {
+ "type": "integer",
+ "description": "Cloud media count"
+ }
+ }
+ }
+ }
+ },
+ "error": {
+ "type": "integer",
+ "description": "Error code",
+ "enum": [0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 40, 1000]
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/Limit"
+ },
+ {
+ "$ref": "#/components/parameters/Offset"
+ }
+ ]
+ }
+ },
"/api/v2/volumes/{mediaid}/prune": {
"put": {
"tags": ["volumes"],
}
}
},
+ "VolumeOverview": {
+ "type": "object",
+ "properties": {
+ "volumename": {
+ "type": "string",
+ "description": "Volume name"
+ },
+ "pool": {
+ "type": "string",
+ "description": "Pool name"
+ },
+ "storage": {
+ "type": "string",
+ "description": "Storage name"
+ },
+ "volbytes": {
+ "type": "integer",
+ "description": "Volume bytes"
+ },
+ "volabytes": {
+ "type": "integer",
+ "description": "Volume compressed bytes"
+ },
+ "inchanger": {
+ "type": "integer",
+ "description": "InChanger flag"
+ },
+ "slot": {
+ "type": "integer",
+ "description": "Slot number"
+ },
+ "expiresin": {
+ "type": "integer",
+ "description": "When volume expire in UNIX timestamp form"
+ }
+ }
+ },
"FileSet": {
"type": "object",
"properties": {