From: Marcin Haba Date: Fri, 19 Aug 2022 12:13:22 +0000 (+0200) Subject: baculum: Add search Bacula items endpoint X-Git-Tag: Release-13.0.2~64 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0d94f2b2734e1571cb84bad206f8d55c7a681434;p=thirdparty%2Fbacula.git baculum: Add search Bacula items endpoint --- diff --git a/gui/baculum/protected/API/Modules/Bconsole.php b/gui/baculum/protected/API/Modules/Bconsole.php index e65892265..cf50787ee 100644 --- a/gui/baculum/protected/API/Modules/Bconsole.php +++ b/gui/baculum/protected/API/Modules/Bconsole.php @@ -98,7 +98,8 @@ class Bconsole extends APIModule { '.ls', 'setbandwidth', '.query', - '.jlist' + '.jlist', + '.search' ); private $config; diff --git a/gui/baculum/protected/API/Modules/ConsoleOutputQueryPage.php b/gui/baculum/protected/API/Modules/ConsoleOutputQueryPage.php index 23fa33e7c..053647e0f 100644 --- a/gui/baculum/protected/API/Modules/ConsoleOutputQueryPage.php +++ b/gui/baculum/protected/API/Modules/ConsoleOutputQueryPage.php @@ -40,7 +40,7 @@ abstract class ConsoleOutputQueryPage extends ConsoleOutputPage { protected function parseOutputKeyValue(array $output) { $ret = []; for ($i = 0; $i < count($output); $i++) { - if (preg_match('/(?P\w+)=(?P.+?)$/i', $output[$i], $matches) === 1) { + if (preg_match('/(?P\w+)=(?P.*?)$/i', $output[$i], $matches) === 1) { $ret[$matches['key']] = $matches['value']; } } diff --git a/gui/baculum/protected/API/Pages/API/SearchItems.php b/gui/baculum/protected/API/Pages/API/SearchItems.php new file mode 100644 index 000000000..9e1fdca32 --- /dev/null +++ b/gui/baculum/protected/API/Pages/API/SearchItems.php @@ -0,0 +1,162 @@ + + * @category API + * @package Baculum API + */ +class SearchItems extends ConsoleOutputQueryPage { + + const CATEGORY_ALL = 'all'; + const CATEGORY_CLIENT = 'client'; + const CATEGORY_JOB = 'job'; + const CATEGORY_VOLUME = 'volume'; + + public function get() { + $misc = $this->getModule('misc'); + + $out_format = ConsoleOutputPage::OUTPUT_FORMAT_RAW; + if ($this->Request->contains('output') && $this->isOutputFormatValid($this->Request['output'])) { + $out_format = $this->Request['output']; + } + $text = $this->Request->contains('text') && $misc->isValidName($this->Request['text']) ? $this->Request['text'] : null; + $category = self::CATEGORY_ALL; // default category + if ($this->Request->contains('category') && $this->categoryExists($this->Request['category'])) { + $category = $this->Request['category']; + } + + if (is_null($text)) { + // no text, do nothing + $this->output = []; + $this->error = BconsoleError::ERROR_NO_ERRORS; + return; + } + + $params = [ + 'text' => $text, + 'category' => $category + ]; + + $out = new \StdClass; + if ($out_format === ConsoleOutputPage::OUTPUT_FORMAT_RAW) { + $out = $this->getRawOutput($params); + } elseif($out_format === ConsoleOutputPage::OUTPUT_FORMAT_JSON) { + $out = $this->getJSONOutput($params); + } + + if ($out->exitcode === 0) { + $this->output = $out->output; + $this->error = BconsoleError::ERROR_NO_ERRORS; + } else { + $this->output = BconsoleError::MSG_ERROR_WRONG_EXITCODE . $out->output; + $this->error = BconsoleError::ERROR_WRONG_EXITCODE; + $this->getModule('logging')->log( + Logging::CATEGORY_EXECUTE, + $this->output . ", Error={$this->error}" + ); + } + } + + /** + * Get search command output from console in raw format. + * + * @param array $params command parameters + * @return StdClass object with output and exitcode + */ + protected function getRawOutput($params = []) { + $ret = $this->getModule('bconsole')->bconsoleCommand( + $this->director, + [ + '.search', + 'category="' . $params['category'] . '"', + 'text="' . $params['text'] . '"' + ] + ); + if ($ret->exitcode !== 0) { + $ret->output = []; // don't provide errors to output, only in logs + $this->getModule('logging')->log( + Logging::CATEGORY_EXECUTE, + 'Wrong output from RAW search items: ' . implode(PHP_EOL, $ret->output) + ); + } + return $ret; + } + + /** + * Get search items results in JSON format. + * + * @param array $params command parameters + * @return StdClass object with output and exitcode + */ + protected function getJSONOutput($params = []) { + $ret = $this->getRawOutput($params); + if ($ret->exitcode === 0) { + $result = $this->parseOutputKeyValue($ret->output); + if (key_exists('error', $result) && $result['error'] === '0') { + $ret->output = (object)[ + 'client' => !empty($result['client']) ? explode(',', $result['client']) : [], + 'volume' => !empty($result['volume']) ? explode(',', $result['volume']) : [], + 'job' => !empty($result['job']) ? explode(',', $result['job']) : [] + ]; + } else { + $ret->output = []; // don't provide errors to output, only in logs + $this->getModule('logging')->log( + Logging::CATEGORY_EXECUTE, + 'Wrong output from .search command output: ' . implode(PHP_EOL, $result) + ); + } + } + return $ret; + } + + /** + * Check if category exists. + * + * @param string $category category + * @return bool true if exists, otherwise false + */ + private function categoryExists($category) { + $cats = $this->getCategories(); + return in_array($category, $cats); + } + + /** + * Get all supported categories. + * return array category list + */ + private function getCategories() { + return [ + self::CATEGORY_ALL, + self::CATEGORY_VOLUME, + self::CATEGORY_CLIENT, + self::CATEGORY_JOB + ]; + } +} diff --git a/gui/baculum/protected/API/Pages/API/endpoints.xml b/gui/baculum/protected/API/Pages/API/endpoints.xml index 102457dfe..f0bdf9f61 100644 --- a/gui/baculum/protected/API/Pages/API/endpoints.xml +++ b/gui/baculum/protected/API/Pages/API/endpoints.xml @@ -9,6 +9,7 @@ + diff --git a/gui/baculum/protected/API/openapi_baculum.json b/gui/baculum/protected/API/openapi_baculum.json index 71a36ce4a..3c5af0a56 100644 --- a/gui/baculum/protected/API/openapi_baculum.json +++ b/gui/baculum/protected/API/openapi_baculum.json @@ -6949,6 +6949,84 @@ } ] } + }, + "/api/v2/search": { + "get": { + "tags": ["tools"], + "summary": "Search for Bacula items (clients, jobs, volumes)", + "description": "Search for Bacula items (clients, jobs, volumes)", + "responses": { + "200": { + "description": "Bacula items (clients, jobs and volumes)", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "output": { + "type": "object", + "properties": { + "client": { + "type": "array", + "description": "Bacula clients", + "items": { + "description": "Client name", + "type": "string" + } + }, + "volume": { + "type": "array", + "description": "Bacula volumes", + "items": { + "description": "Volume names", + "type": "string" + } + }, + "job": { + "type": "array", + "description": "Bacula jobs", + "items": { + "description": "Job names", + "type": "string" + } + } + } + }, + "error": { + "type": "integer", + "description": "Error code", + "enum": [0, 1, 4, 5, 6, 7, 11, 1000] + } + } + } + } + } + } + }, + "parameters": [ + { + "name": "text", + "in": "query", + "required": false, + "description": "Text to search items", + "schema": { + "type": "string" + } + }, + { + "name": "category", + "in": "query", + "required": false, + "description": "Category to search (all, job, client, volume). Default is 'all'.", + "schema": { + "type": "string" + } + }, + { + "$ref": "#/components/parameters/Output" + } + ] + } } }, "definitions": {