]> git.ipfire.org Git - thirdparty/bacula.git/commitdiff
baculum: Add support for cloud storage commands
authorMarcin Haba <marcin.haba@bacula.pl>
Mon, 30 Jan 2023 15:55:41 +0000 (16:55 +0100)
committerMarcin Haba <marcin.haba@bacula.pl>
Sun, 5 Mar 2023 06:06:30 +0000 (07:06 +0100)
Supported commands:
 - list
 - prune
 - truncate
 - upload

gui/baculum/protected/API/Modules/Bconsole.php
gui/baculum/protected/API/Modules/ConsoleOutputAPI2Page.php [new file with mode: 0644]
gui/baculum/protected/API/Pages/API/StorageCloudList.php [new file with mode: 0644]
gui/baculum/protected/API/Pages/API/StorageCloudPrune.php [new file with mode: 0644]
gui/baculum/protected/API/Pages/API/StorageCloudTruncate.php [new file with mode: 0644]
gui/baculum/protected/API/Pages/API/StorageCloudUpload.php [new file with mode: 0644]
gui/baculum/protected/API/Pages/API/endpoints.xml
gui/baculum/protected/API/openapi_baculum.json

index dc380e149f20ac124e9b75306c1baef28de044cb..fa3f525b48d8456e8468e3fd7016c73a86704893 100644 (file)
@@ -101,7 +101,8 @@ class Bconsole extends APIModule {
                '.query',
                '.jlist',
                '.search',
-               '@putfile'
+               '@putfile',
+               'cloud'
        );
 
        private $config;
diff --git a/gui/baculum/protected/API/Modules/ConsoleOutputAPI2Page.php b/gui/baculum/protected/API/Modules/ConsoleOutputAPI2Page.php
new file mode 100644 (file)
index 0000000..4e990d2
--- /dev/null
@@ -0,0 +1,54 @@
+<?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.
+ */
+
+namespace Baculum\API\Modules;
+
+/**
+ * Get console output for generic API 2 type bconsole commands.
+ *
+ * @author Marcin Haba <marcin.haba@bacula.pl>
+ * @category API
+ * @package Baculum API
+ */
+abstract class ConsoleOutputAPI2Page extends ConsoleOutputPage {
+
+       /**
+        * Parse API 2 interface type command output in "key=value" form.
+        *
+        * @param array $output command output
+        * @return array parsed output
+        */
+       protected function parseOutput(array $output) {
+               $ret = $vals = [];
+               $out_len = count($output);
+               for ($i = 0; $i < $out_len; $i++) {
+                       if (preg_match('/^\s*(?P<key>\w+)\s*=\s*(?P<value>.*?)$/i', $output[$i], $matches) === 1) {
+                               $vals[$matches['key']] = $matches['value'];
+                       }
+                       if ((empty($output[$i]) || ($i == ($out_len - 1))) && count($vals) > 0) {
+                               $ret[] = $vals;
+                               $vals = [];
+                       }
+               }
+               return $ret;
+       }
+}
diff --git a/gui/baculum/protected/API/Pages/API/StorageCloudList.php b/gui/baculum/protected/API/Pages/API/StorageCloudList.php
new file mode 100644 (file)
index 0000000..7e7432a
--- /dev/null
@@ -0,0 +1,116 @@
+<?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\Bconsole;
+use Baculum\API\Modules\ConsoleOutputPage;
+use Baculum\API\Modules\ConsoleOutputAPI2Page;
+use Baculum\Common\Modules\Errors\GenericError;
+use Baculum\Common\Modules\Errors\StorageError;
+
+
+/**
+ * Cloud storage volume list endpoint.
+ *
+ * @author Marcin Haba <marcin.haba@bacula.pl>
+ * @category API
+ * @package Baculum API
+ */
+class StorageCloudList extends ConsoleOutputAPI2Page {
+
+       public function get() {
+               $misc = $this->getModule('misc');
+               $storageid = $this->Request->contains('id') ? (int)$this->Request['id'] : 0;
+               $storage = $this->getModule('storage')->getStorageById($storageid);
+               $volume = $this->Request->contains('volume') && $misc->isValidName($this->Request['volume']) ? $this->Request['volume'] : null;
+               $drive = $this->Request->contains('drive') && $misc->isValidInteger($this->Request['drive']) ? (int)$this->Request['drive'] : null;
+               $out_format = $this->Request->contains('output') && $this->isOutputFormatValid($this->Request['output']) ? $this->Request['output'] : parent::OUTPUT_FORMAT_RAW;
+               $result = $this->getModule('bconsole')->bconsoleCommand(
+                       $this->director,
+                       array('.storage')
+               );
+
+               $storage_exists = false;
+               if ($result->exitcode === 0) {
+                       $storage_exists = (is_object($storage) && in_array($storage->name, $result->output));
+               }
+
+               if ($storage_exists == false) {
+                       // Storage doesn't exist or is not available for user because of ACL restrictions
+                       $this->output = StorageError::MSG_ERROR_STORAGE_DOES_NOT_EXISTS;
+                       $this->error = StorageError::ERROR_STORAGE_DOES_NOT_EXISTS;
+                       return;
+               }
+
+               $out = (object)['output' => [], 'error' => 0];
+               $params = [
+                       'storage' => $storage->name
+               ];
+               if (is_string($volume)) {
+                       $params['volume'] = $volume;
+               }
+               if (is_int($drive)) {
+                       $params['drive'] = $drive;
+               }
+               if ($out_format === ConsoleOutputPage::OUTPUT_FORMAT_RAW) {
+                       $out = $this->getRawOutput($params);
+               } elseif ($out_format === ConsoleOutputPage::OUTPUT_FORMAT_JSON) {
+                       $out = $this->getJSONOutput($params);
+               }
+               $this->output = $out['output'];
+               $this->error = $out['error'];
+       }
+
+       protected function getRawOutput($params = [], $ptype = null) {
+               $cmd = ['cloud', 'list'];
+               foreach ($params as $key => $val) {
+                       if (is_null($val)) {
+                               $cmd[] = $key;
+                       } else {
+                               $cmd[] = $key . '="' . $val . '"';
+                       }
+               }
+               // traditional cloud storage truncate volume output
+               $result = $this->getModule('bconsole')->bconsoleCommand(
+                       $this->director,
+                       $cmd,
+                       $ptype
+               );
+               $error = $result->exitcode == 0 ? $result->exitcode : GenericError::ERROR_WRONG_EXITCODE;
+               $ret = [
+                       'output' => $result->output,
+                       'error' => $error
+               ];
+               return $ret;
+       }
+
+       protected function getJSONOutput($params = []) {
+               $result = $this->getRawOutput(
+                       $params,
+                       Bconsole::PTYPE_API_CMD
+               );
+               if ($result['error'] === 0) {
+                       $result['output'] = $this->parseOutput($result['output']);
+               }
+               return $result;
+       }
+}
diff --git a/gui/baculum/protected/API/Pages/API/StorageCloudPrune.php b/gui/baculum/protected/API/Pages/API/StorageCloudPrune.php
new file mode 100644 (file)
index 0000000..5de182a
--- /dev/null
@@ -0,0 +1,118 @@
+<?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\Common\Modules\Errors\GenericError;
+use Baculum\Common\Modules\Errors\StorageError;
+
+
+/**
+ * Cloud storage volume prune endpoint.
+ *
+ * @author Marcin Haba <marcin.haba@bacula.pl>
+ * @category API
+ * @package Baculum API
+ */
+class StorageCloudPrune extends BaculumAPIServer {
+
+       public function get() {
+               $misc = $this->getModule('misc');
+               $storageid = $this->Request->contains('id') ? (int)$this->Request['id'] : 0;
+               $storage = $this->getModule('storage')->getStorageById($storageid);
+               $volume = $this->Request->contains('volume') && $misc->isValidName($this->Request['volume']) ? $this->Request['volume'] : null;
+               $pool = $this->Request->contains('pool') && $misc->isValidName($this->Request['pool']) ? $this->Request['pool'] : null;
+               $allpools = $this->Request->contains('allpools') && $misc->isValidBooleanTrue($this->Request['allpools']) ? true : null;
+               $allfrompool = $this->Request->contains('allfrompool') && $misc->isValidBooleanTrue($this->Request['allfrompool']) ? true : null;
+               $mediatype = $this->Request->contains('mediatype') && $misc->isValidName($this->Request['mediatype']) ? $this->Request['mediatype'] : null;
+               $drive = $this->Request->contains('drive') && $misc->isValidInteger($this->Request['drive']) ? (int)$this->Request['drive'] : null;
+               $slots = $this->Request->contains('slots') && $misc->isValidRange($this->Request['slots']) ? $this->Request['slots'] : null;
+               $result = $this->getModule('bconsole')->bconsoleCommand(
+                       $this->director,
+                       array('.storage')
+               );
+
+               $storage_exists = false;
+               if ($result->exitcode === 0) {
+                       $storage_exists = (is_object($storage) && in_array($storage->name, $result->output));
+               }
+
+               if ($storage_exists == false) {
+                       // Storage doesn't exist or is not available for user because of ACL restrictions
+                       $this->output = StorageError::MSG_ERROR_STORAGE_DOES_NOT_EXISTS;
+                       $this->error = StorageError::ERROR_STORAGE_DOES_NOT_EXISTS;
+                       return;
+               }
+
+               $out = (object)['output' => [], 'error' => 0];
+               $params = [
+                       'storage' => $storage->name
+               ];
+               if (is_string($volume)) {
+                       $params['volume'] = $volume;
+               }
+               if (is_bool($allpools)) {
+                       $params['allpools'] = null;
+               }
+               if (is_bool($allfrompool)) {
+                       $params['allfrompool'] = null;
+               }
+               if (is_string($pool)) {
+                       $params['pool'] = $pool;
+               }
+               if (is_string($mediatype)) {
+                       $params['mediatype'] = $mediatype;
+               }
+               if (is_int($drive)) {
+                       $params['drive'] = $drive;
+               }
+               // Uncomment when slots parameter will be supported
+               /*
+               if (is_string($slots)) {
+                       $params['slots'] = $slots;
+               }
+               */
+               $out = $this->getRawOutput($params);
+               $this->output = $out['output'];
+               $this->error = $out['error'];
+       }
+
+       protected function getRawOutput($params = []) {
+               $cmd = ['cloud', 'prune'];
+               foreach ($params as $key => $val) {
+                       if (is_null($val)) {
+                               $cmd[] = $key;
+                       } else {
+                               $cmd[] = $key . '="' . $val . '"';
+                       }
+               }
+               // traditional cloud storage truncate volume output
+               $result = $this->getModule('bconsole')->bconsoleCommand(
+                       $this->director,
+                       $cmd
+               );
+               $error = $result->exitcode == 0 ? $result->exitcode : GenericError::ERROR_WRONG_EXITCODE;
+               $ret = [
+                       'output' => $result->output,
+                       'error' => $error
+               ];
+               return $ret;
+       }
+}
diff --git a/gui/baculum/protected/API/Pages/API/StorageCloudTruncate.php b/gui/baculum/protected/API/Pages/API/StorageCloudTruncate.php
new file mode 100644 (file)
index 0000000..3945a95
--- /dev/null
@@ -0,0 +1,118 @@
+<?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\Common\Modules\Errors\GenericError;
+use Baculum\Common\Modules\Errors\StorageError;
+
+
+/**
+ * Cloud storage volume truncate endpoint.
+ *
+ * @author Marcin Haba <marcin.haba@bacula.pl>
+ * @category API
+ * @package Baculum API
+ */
+class StorageCloudTruncate extends BaculumAPIServer {
+
+       public function get() {
+               $misc = $this->getModule('misc');
+               $storageid = $this->Request->contains('id') ? (int)$this->Request['id'] : 0;
+               $storage = $this->getModule('storage')->getStorageById($storageid);
+               $volume = $this->Request->contains('volume') && $misc->isValidName($this->Request['volume']) ? $this->Request['volume'] : null;
+               $pool = $this->Request->contains('pool') && $misc->isValidName($this->Request['pool']) ? $this->Request['pool'] : null;
+               $allpools = $this->Request->contains('allpools') && $misc->isValidBooleanTrue($this->Request['allpools']) ? true : null;
+               $allfrompool = $this->Request->contains('allfrompool') && $misc->isValidBooleanTrue($this->Request['allfrompool']) ? true : null;
+               $mediatype = $this->Request->contains('mediatype') && $misc->isValidName($this->Request['mediatype']) ? $this->Request['mediatype'] : null;
+               $drive = $this->Request->contains('drive') && $misc->isValidInteger($this->Request['drive']) ? (int)$this->Request['drive'] : null;
+               $slots = $this->Request->contains('slots') && $misc->isValidRange($this->Request['slots']) ? $this->Request['slots'] : null;
+               $result = $this->getModule('bconsole')->bconsoleCommand(
+                       $this->director,
+                       array('.storage')
+               );
+
+               $storage_exists = false;
+               if ($result->exitcode === 0) {
+                       $storage_exists = (is_object($storage) && in_array($storage->name, $result->output));
+               }
+
+               if ($storage_exists == false) {
+                       // Storage doesn't exist or is not available for user because of ACL restrictions
+                       $this->output = StorageError::MSG_ERROR_STORAGE_DOES_NOT_EXISTS;
+                       $this->error = StorageError::ERROR_STORAGE_DOES_NOT_EXISTS;
+                       return;
+               }
+
+               $out = (object)['output' => [], 'error' => 0];
+               $params = [
+                       'storage' => $storage->name
+               ];
+               if (is_string($volume)) {
+                       $params['volume'] = $volume;
+               }
+               if (is_bool($allpools)) {
+                       $params['allpools'] = null;
+               }
+               if (is_bool($allfrompool)) {
+                       $params['allfrompool'] = null;
+               }
+               if (is_string($pool)) {
+                       $params['pool'] = $pool;
+               }
+               if (is_string($mediatype)) {
+                       $params['mediatype'] = $mediatype;
+               }
+               if (is_int($drive)) {
+                       $params['drive'] = $drive;
+               }
+               // Uncomment when slots parameter will be supported
+               /*
+               if (is_string($slots)) {
+                       $params['slots'] = $slots;
+               }
+               */
+               $out = $this->getRawOutput($params);
+               $this->output = $out['output'];
+               $this->error = $out['error'];
+       }
+
+       protected function getRawOutput($params = []) {
+               $cmd = ['cloud', 'truncate'];
+               foreach ($params as $key => $val) {
+                       if (is_null($val)) {
+                               $cmd[] = $key;
+                       } else {
+                               $cmd[] = $key . '="' . $val . '"';
+                       }
+               }
+               // traditional cloud storage truncate volume output
+               $result = $this->getModule('bconsole')->bconsoleCommand(
+                       $this->director,
+                       $cmd
+               );
+               $error = $result->exitcode == 0 ? $result->exitcode : GenericError::ERROR_WRONG_EXITCODE;
+               $ret = [
+                       'output' => $result->output,
+                       'error' => $error
+               ];
+               return $ret;
+       }
+}
diff --git a/gui/baculum/protected/API/Pages/API/StorageCloudUpload.php b/gui/baculum/protected/API/Pages/API/StorageCloudUpload.php
new file mode 100644 (file)
index 0000000..2943043
--- /dev/null
@@ -0,0 +1,118 @@
+<?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\Common\Modules\Errors\GenericError;
+use Baculum\Common\Modules\Errors\StorageError;
+
+
+/**
+ * Cloud storage volume upload endpoint.
+ *
+ * @author Marcin Haba <marcin.haba@bacula.pl>
+ * @category API
+ * @package Baculum API
+ */
+class StorageCloudUpload extends BaculumAPIServer {
+
+       public function get() {
+               $misc = $this->getModule('misc');
+               $storageid = $this->Request->contains('id') ? (int)$this->Request['id'] : 0;
+               $storage = $this->getModule('storage')->getStorageById($storageid);
+               $volume = $this->Request->contains('volume') && $misc->isValidName($this->Request['volume']) ? $this->Request['volume'] : null;
+               $pool = $this->Request->contains('pool') && $misc->isValidName($this->Request['pool']) ? $this->Request['pool'] : null;
+               $allpools = $this->Request->contains('allpools') && $misc->isValidBooleanTrue($this->Request['allpools']) ? true : null;
+               $allfrompool = $this->Request->contains('allfrompool') && $misc->isValidBooleanTrue($this->Request['allfrompool']) ? true : null;
+               $mediatype = $this->Request->contains('mediatype') && $misc->isValidName($this->Request['mediatype']) ? $this->Request['mediatype'] : null;
+               $drive = $this->Request->contains('drive') && $misc->isValidInteger($this->Request['drive']) ? (int)$this->Request['drive'] : null;
+               $slots = $this->Request->contains('slots') && $misc->isValidRange($this->Request['slots']) ? $this->Request['slots'] : null;
+               $result = $this->getModule('bconsole')->bconsoleCommand(
+                       $this->director,
+                       array('.storage')
+               );
+
+               $storage_exists = false;
+               if ($result->exitcode === 0) {
+                       $storage_exists = (is_object($storage) && in_array($storage->name, $result->output));
+               }
+
+               if ($storage_exists == false) {
+                       // Storage doesn't exist or is not available for user because of ACL restrictions
+                       $this->output = StorageError::MSG_ERROR_STORAGE_DOES_NOT_EXISTS;
+                       $this->error = StorageError::ERROR_STORAGE_DOES_NOT_EXISTS;
+                       return;
+               }
+
+               $out = (object)['output' => [], 'error' => 0];
+               $params = [
+                       'storage' => $storage->name
+               ];
+               if (is_string($volume)) {
+                       $params['volume'] = $volume;
+               }
+               if (is_bool($allpools)) {
+                       $params['allpools'] = null;
+               }
+               if (is_bool($allfrompool)) {
+                       $params['allfrompool'] = null;
+               }
+               if (is_string($pool)) {
+                       $params['pool'] = $pool;
+               }
+               if (is_string($mediatype)) {
+                       $params['mediatype'] = $mediatype;
+               }
+               if (is_int($drive)) {
+                       $params['drive'] = $drive;
+               }
+               // Uncomment when slots parameter will be supported
+               /*
+               if (is_string($slots)) {
+                       $params['slots'] = $slots;
+               }
+               */
+               $out = $this->getRawOutput($params);
+               $this->output = $out['output'];
+               $this->error = $out['error'];
+       }
+
+       protected function getRawOutput($params = []) {
+               $cmd = ['cloud', 'upload'];
+               foreach ($params as $key => $val) {
+                       if (is_null($val)) {
+                               $cmd[] = $key;
+                       } else {
+                               $cmd[] = $key . '="' . $val . '"';
+                       }
+               }
+               // traditional cloud storage truncate volume output
+               $result = $this->getModule('bconsole')->bconsoleCommand(
+                       $this->director,
+                       $cmd
+               );
+               $error = $result->exitcode == 0 ? $result->exitcode : GenericError::ERROR_WRONG_EXITCODE;
+               $ret = [
+                       'output' => $result->output,
+                       'error' => $error
+               ];
+               return $ret;
+       }
+}
index 45743da41349e9dacee2fb849d3ecc73cf326273..00aa6bfa911c42814dc33afffa9dd3fc5b2f4a2f 100644 (file)
        <url ServiceParameter="StorageMount" pattern="api/v2/storages/{id}/mount/" parameters.id="\d+" />
        <url ServiceParameter="StorageUmount" pattern="api/v2/storages/{id}/umount/" parameters.id="\d+" />
        <url ServiceParameter="StorageRelease" pattern="api/v2/storages/{id}/release/" parameters.id="\d+" />
+       <url ServiceParameter="StorageCloudTruncate" pattern="api/v2/storages/{id}/cloud/truncate/" parameters.id="\d+" />
+       <url ServiceParameter="StorageCloudPrune" pattern="api/v2/storages/{id}/cloud/prune/" parameters.id="\d+" />
+       <url ServiceParameter="StorageCloudUpload" pattern="api/v2/storages/{id}/cloud/upload/" parameters.id="\d+" />
+       <url ServiceParameter="StorageCloudList" pattern="api/v2/storages/{id}/cloud/list/" parameters.id="\d+" />
        <!-- devices endpoints -->
        <url ServiceParameter="ChangerDriveLoad" pattern="api/v2/devices/{device_name}/load/" parameters.device_name="[a-zA-Z0-9:.\-_ ]+" />
        <url ServiceParameter="ChangerDriveUnload" pattern="api/v2/devices/{device_name}/unload/" parameters.device_name="[a-zA-Z0-9:.\-_ ]+" />
index 55cfa6ad4e0151f47dd03c66558585f7a8f09817..5fc72718ec8684c6d1b28530a9402d7864cf3451 100644 (file)
                                ]
                        }
                },
+               "/api/v2/storages/{storageid}/cloud/upload": {
+                       "get": {
+                               "tags": ["storages"],
+                               "summary": "Upload cloud volumes",
+                               "description": "Upload cloud volumes",
+                               "responses": {
+                                       "200": {
+                                               "description": "Upload cloud volume output",
+                                               "content": {
+                                                       "application/json": {
+                                                               "schema": {
+                                                                       "type": "object",
+                                                                       "properties": {
+                                                                               "output": {
+                                                                                       "type": "array",
+                                                                                       "items": {
+                                                                                               "type": "string",
+                                                                                               "description": "Upload cloud volume output"
+                                                                                       }
+                                                                               },
+                                                                               "error": {
+                                                                                       "type": "integer",
+                                                                                       "description": "Error code",
+                                                                                       "enum": [0, 1, 2, 3, 4, 5, 6, 7, 11, 20, 1000]
+                                                                               }
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               },
+                               "parameters": [
+                                       {
+                                       "$ref": "#/components/parameters/StorageId"
+                                       },
+                                       {
+                                               "name": "volume",
+                                               "in": "query",
+                                               "required": false,
+                                               "description": "Volume name",
+                                               "schema": {
+                                                       "type": "string"
+                                               }
+                                       },
+                                       {
+                                               "name": "pool",
+                                               "in": "query",
+                                               "required": false,
+                                               "description": "Pool name",
+                                               "schema": {
+                                                       "type": "string"
+                                               }
+                                       },
+                                       {
+                                               "name": "allpools",
+                                               "in": "query",
+                                               "required": false,
+                                               "description": "Get volumes from all pools",
+                                               "schema": {
+                                                       "type": "boolean"
+                                               }
+                                       },
+                                       {
+                                               "name": "allfrompool",
+                                               "in": "query",
+                                               "required": false,
+                                               "description": "Get all from given pool in 'pool' parameter",
+                                               "schema": {
+                                                       "type": "boolean"
+                                               }
+                                       },
+                                       {
+                                               "name": "mediatype",
+                                               "in": "query",
+                                               "required": false,
+                                               "description": "Media type",
+                                               "schema": {
+                                                       "type": "string"
+                                               }
+                                       },
+                                       {
+                                               "name": "drive",
+                                               "in": "query",
+                                               "required": false,
+                                               "description": "Drive number",
+                                               "schema": {
+                                                       "type": "string"
+                                               }
+                                       }
+                               ]
+                       }
+               },
+               "/api/v2/storages/{storageid}/cloud/truncate": {
+                       "get": {
+                               "tags": ["storages"],
+                               "summary": "Truncate cloud volumes",
+                               "description": "Truncate cloud volumes",
+                               "responses": {
+                                       "200": {
+                                               "description": "Truncate cloud volume output",
+                                               "content": {
+                                                       "application/json": {
+                                                               "schema": {
+                                                                       "type": "object",
+                                                                       "properties": {
+                                                                               "output": {
+                                                                                       "type": "array",
+                                                                                       "items": {
+                                                                                               "type": "string",
+                                                                                               "description": "Truncate cloud volume output"
+                                                                                       }
+                                                                               },
+                                                                               "error": {
+                                                                                       "type": "integer",
+                                                                                       "description": "Error code",
+                                                                                       "enum": [0, 1, 2, 3, 4, 5, 6, 7, 11, 20, 1000]
+                                                                               }
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               },
+                               "parameters": [
+                                       {
+                                       "$ref": "#/components/parameters/StorageId"
+                                       },
+                                       {
+                                               "name": "volume",
+                                               "in": "query",
+                                               "required": false,
+                                               "description": "Volume name",
+                                               "schema": {
+                                                       "type": "string"
+                                               }
+                                       },
+                                       {
+                                               "name": "pool",
+                                               "in": "query",
+                                               "required": false,
+                                               "description": "Pool name",
+                                               "schema": {
+                                                       "type": "string"
+                                               }
+                                       },
+                                       {
+                                               "name": "allpools",
+                                               "in": "query",
+                                               "required": false,
+                                               "description": "Get volumes from all pools",
+                                               "schema": {
+                                                       "type": "boolean"
+                                               }
+                                       },
+                                       {
+                                               "name": "allfrompool",
+                                               "in": "query",
+                                               "required": false,
+                                               "description": "Get all from given pool in 'pool' parameter",
+                                               "schema": {
+                                                       "type": "boolean"
+                                               }
+                                       },
+                                       {
+                                               "name": "mediatype",
+                                               "in": "query",
+                                               "required": false,
+                                               "description": "Media type",
+                                               "schema": {
+                                                       "type": "string"
+                                               }
+                                       },
+                                       {
+                                               "name": "drive",
+                                               "in": "query",
+                                               "required": false,
+                                               "description": "Drive number",
+                                               "schema": {
+                                                       "type": "string"
+                                               }
+                                       }
+                               ]
+                       }
+               },
+               "/api/v2/storages/{storageid}/cloud/prune": {
+                       "get": {
+                               "tags": ["storages"],
+                               "summary": "Prune cloud volumes",
+                               "description": "Prune cloud volumes",
+                               "responses": {
+                                       "200": {
+                                               "description": "Prune cloud volume output",
+                                               "content": {
+                                                       "application/json": {
+                                                               "schema": {
+                                                                       "type": "object",
+                                                                       "properties": {
+                                                                               "output": {
+                                                                                       "type": "array",
+                                                                                       "items": {
+                                                                                               "type": "string",
+                                                                                               "description": "Prune cloud volume output"
+                                                                                       }
+                                                                               },
+                                                                               "error": {
+                                                                                       "type": "integer",
+                                                                                       "description": "Error code",
+                                                                                       "enum": [0, 1, 2, 3, 4, 5, 6, 7, 11, 20, 1000]
+                                                                               }
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               },
+                               "parameters": [
+                                       {
+                                       "$ref": "#/components/parameters/StorageId"
+                                       },
+                                       {
+                                               "name": "volume",
+                                               "in": "query",
+                                               "required": false,
+                                               "description": "Volume name",
+                                               "schema": {
+                                                       "type": "string"
+                                               }
+                                       },
+                                       {
+                                               "name": "pool",
+                                               "in": "query",
+                                               "required": false,
+                                               "description": "Pool name",
+                                               "schema": {
+                                                       "type": "string"
+                                               }
+                                       },
+                                       {
+                                               "name": "allpools",
+                                               "in": "query",
+                                               "required": false,
+                                               "description": "Get volumes from all pools",
+                                               "schema": {
+                                                       "type": "boolean"
+                                               }
+                                       },
+                                       {
+                                               "name": "allfrompool",
+                                               "in": "query",
+                                               "required": false,
+                                               "description": "Get all from given pool in 'pool' parameter",
+                                               "schema": {
+                                                       "type": "boolean"
+                                               }
+                                       },
+                                       {
+                                               "name": "mediatype",
+                                               "in": "query",
+                                               "required": false,
+                                               "description": "Media type",
+                                               "schema": {
+                                                       "type": "string"
+                                               }
+                                       },
+                                       {
+                                               "name": "drive",
+                                               "in": "query",
+                                               "required": false,
+                                               "description": "Drive number",
+                                               "schema": {
+                                                       "type": "string"
+                                               }
+                                       }
+                               ]
+                       }
+               },
+               "/api/v2/storages/{storageid}/cloud/list": {
+                       "get": {
+                               "tags": ["storages"],
+                               "summary": "List cloud volumes",
+                               "description": "List cloud volumes",
+                               "responses": {
+                                       "200": {
+                                               "description": "List cloud volume output",
+                                               "content": {
+                                                       "application/json": {
+                                                               "schema": {
+                                                                       "type": "object",
+                                                                       "properties": {
+                                                                               "output": {
+                                                                                       "type": "array",
+                                                                                       "items": {
+                                                                                               "type": "string",
+                                                                                               "description": "List cloud volume output"
+                                                                                       }
+                                                                               },
+                                                                               "error": {
+                                                                                       "type": "integer",
+                                                                                       "description": "Error code",
+                                                                                       "enum": [0, 1, 2, 3, 4, 5, 6, 7, 11, 20, 1000]
+                                                                               }
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               },
+                               "parameters": [
+                                       {
+                                               "$ref": "#/components/parameters/StorageId"
+                                       },
+                                       {
+                                               "$ref": "#/components/parameters/Output"
+                                       },
+                                       {
+                                               "name": "volume",
+                                               "in": "query",
+                                               "required": false,
+                                               "description": "Volume name",
+                                               "schema": {
+                                                       "type": "string"
+                                               }
+                                       },
+                                       {
+                                               "name": "drive",
+                                               "in": "query",
+                                               "required": false,
+                                               "description": "Drive number",
+                                               "schema": {
+                                                       "type": "string"
+                                               }
+                                       }
+                               ]
+                       }
+               },
                "/api/v2/storages/show": {
                        "get": {
                                "tags": ["storages"],