From: Marcin Haba Date: Wed, 10 Jan 2024 10:47:37 +0000 (+0100) Subject: Add endpoint to list AWS cloud buckets X-Git-Tag: Beta-15.0.1~72 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2760cff8d31668f6b6b1450c05f5aca7e5d279bb;p=thirdparty%2Fbacula.git Add endpoint to list AWS cloud buckets --- diff --git a/gui/baculum/protected/API/Modules/AWSCliTool.php b/gui/baculum/protected/API/Modules/AWSCliTool.php new file mode 100644 index 000000000..d450eb0a1 --- /dev/null +++ b/gui/baculum/protected/API/Modules/AWSCliTool.php @@ -0,0 +1,207 @@ + + * @category Module + * @package Baculum API + */ +class AWSCliTool extends APIModule { + + /** + * SUDO command. + */ + const SUDO = 'sudo'; + + /** + * AWS CLI tool command pattern. + */ + const AWS_TOOL_COMMAND_PATTERN = 'LANG=C AWS_ACCESS_KEY_ID="%access_key" AWS_SECRET_ACCESS_KEY="%secret_key" %use_sudo%bin %options 2>&1'; + + /** + * Check if AWS CLI tool is enabled. + * + * @return bool true if it is enabled, otherwise false + */ + private function isToolEnabled() { + // temporary set staticaly to enabled + return true; + } + + /** + * Prepare AWS CLI tool results. + * + * @param mixed $output result output + * @param integer $error error number + * @return array output and error + */ + public function prepareResult($output, $error) { + $result = [ + 'output' => $output, + 'error' => $error + ]; + return $result; + } + + /** + * Prepare and check AWS CLI tool output. + * + * @param array $output command output + * @return mixed array with results or null if output is unable to parse + */ + private function prepareOutput(array $output) { + $output_txt = implode('', $output); + $out = json_decode($output_txt, true); + if (!is_array($out)) { + $this->getModule('logging')->log( + Logging::CATEGORY_EXTERNAL, + "Parse output error: $output_txt" + ); + $out = null; + } + return $out; + } + + /** + * Get sudo command. + * + * @param bool $use_sudo true to use sudo, false otherwise + * @return string sudo command + */ + private function getSudo($use_sudo = false) { + $sudo = ''; + if ($use_sudo === true) { + $sudo = self::SUDO . ' '; + } + return $sudo; + } + + /** + * Execute AWS CLI command. + * + * @param array $params command parameters + * @return mixed array with results or null if AWS CLI is disabled. + */ + public function execCommand($params = []) { + $result = null; + if ($this->isToolEnabled() === true) { + $tool = $this->getTool(); + $result = $this->execTool( + $tool['bin'], + $tool['use_sudo'], + $params + ); + $output = $result['output']; + $error = $result['error']; + if ($error === 0) { + $output = $this->prepareOutput($output); + if (is_null($output)) { + $output = AWSToolError::MSG_ERROR_AWS_TOOL_UNABLE_TO_PARSE_OUTPUT; + $error = AWSToolError::ERROR_AWS_TOOL_UNABLE_TO_PARSE_OUTPUT; + } + } else { + $emsg = PHP_EOL . ' Output:' . implode(PHP_EOL, $output); + $output = AWSToolError::MSG_ERROR_WRONG_EXITCODE . $emsg; + $error = AWSToolError::ERROR_WRONG_EXITCODE; + } + $result = $this->prepareResult($output, $error); + } else { + $output = AWSToolError::MSG_ERROR_AWS_TOOL_DISABLED; + $error = AWSToolError::ERROR_AWS_TOOL_DISABLED; + $result = $this->prepareResult($output, $error); + } + return $result; + } + + /** + * Get AWS CLI tool binary. + * + * @return array AWS CLI binary parameters + */ + private function getTool() { + /** + * Parameters set staticaly because of the temporary AWS CLI implementation. + */ + return [ + 'bin' => 'aws', + 'cfg' => '', + 'use_sudo' => false + ]; + } + + /** + * Execute AWS CLI tool (internal method) + * + * @param string $bin tool binary path + * @param boolean use_sudo true to use sudo, false otherwise + * @return array output and exitcode results + */ + private function execTool($bin, $use_sudo, $params = []) { + $sudo = $this->getSudo($use_sudo); + $cmd = $this->getCmd($sudo, $bin, $params); + exec($cmd, $output, $exitcode); + $this->getModule('logging')->log( + Logging::CATEGORY_EXECUTE, + Logging::prepareOutput($cmd, $output) + ); + $result = $this->prepareResult($output, $exitcode); + return $result; + } + + /** + * Get AWS CLi tool command. + * + * @param string $bin tool binary path + * @param bool $use_sudo use sudo with tool + * @param array $params command parameters + * @return string command + */ + private function getCmd($bin, $use_sudo, $params) { + // Default command pattern + $pattern = self::AWS_TOOL_COMMAND_PATTERN; + $access_key = ''; + if (key_exists('access_key', $params)) { + $access_key = $params['access_key']; + } + $secret_key = ''; + if (key_exists('secret_key', $params)) { + $secret_key = $params['secret_key']; + } + $options = ''; + if (key_exists('options', $params) && is_array($params['options']) && count($params['options']) > 0) { + $options = '"' . implode('" "', $params['options']) . '"'; + } + $pattern = str_replace('%access_key', $access_key, $pattern); + $pattern = str_replace('%secret_key', $secret_key, $pattern); + $pattern = str_replace('%bin', $bin, $pattern); + $pattern = str_replace('%use_sudo', $use_sudo, $pattern); + $pattern = str_replace('%options', $options, $pattern); + return $pattern; + } +} diff --git a/gui/baculum/protected/API/Pages/API/AWSListBuckets.php b/gui/baculum/protected/API/Pages/API/AWSListBuckets.php new file mode 100644 index 000000000..11a78fd01 --- /dev/null +++ b/gui/baculum/protected/API/Pages/API/AWSListBuckets.php @@ -0,0 +1,67 @@ + + * @category API + * @package Baculum API + */ +class AWSListBuckets extends BaculumAPIServer { + + public function get() { + $misc = $this->getModule('misc'); + $access_key = $this->Request->contains('access_key') && $misc->isValidLogin($this->Request['access_key']) ? $this->Request['access_key'] : ''; + $secret_key = $this->Request->contains('secret_key') && $misc->isValidSecret($this->Request['secret_key']) ? $this->Request['secret_key'] : ''; + $endpoint = $this->Request->contains('endpoint') && $misc->isValidURL($this->Request['endpoint']) ? $this->Request['endpoint'] : ''; + $region = $this->Request->contains('region') && $misc->isValidName($this->Request['region']) ? $this->Request['region'] : ''; + if (empty($access_key)) { + $this->error = AWSToolError::ERROR_AWS_MISSING_ACCESS_KEY; + $this->output = AWSToolError::MSG_ERROR_AWS_MISSING_ACCESS_KEY; + return; + } + if (empty($secret_key)) { + $this->error = AWSToolError::ERROR_AWS_MISSING_SECRET_KEY; + $this->output = AWSToolError::MSG_ERROR_AWS_MISSING_SECRET_KEY; + return; + } + $params['access_key'] = $access_key; + $params['secret_key'] = $secret_key; + $params['options'] = [ + 's3api', + 'list-buckets' + ]; + if (!empty($endpoint)) { + $params['options'][] = '--endpoint-url=' . $endpoint; + } + if (!empty($region)) { + $params['options'][] = '--region=' . $region; + } + $result = $this->getModule('aws_tool')->execCommand($params); + $this->output = $result['output']; + $this->error = $result['error']; + } +} diff --git a/gui/baculum/protected/API/Pages/API/config.xml b/gui/baculum/protected/API/Pages/API/config.xml index 4f14a0ac6..c1f8442a7 100644 --- a/gui/baculum/protected/API/Pages/API/config.xml +++ b/gui/baculum/protected/API/Pages/API/config.xml @@ -37,6 +37,7 @@ + diff --git a/gui/baculum/protected/API/Pages/API/endpoints.xml b/gui/baculum/protected/API/Pages/API/endpoints.xml index 0e261779e..f3cef97c8 100644 --- a/gui/baculum/protected/API/Pages/API/endpoints.xml +++ b/gui/baculum/protected/API/Pages/API/endpoints.xml @@ -149,6 +149,10 @@ + + + + diff --git a/gui/baculum/protected/Common/Modules/Errors/AWSToolError.php b/gui/baculum/protected/Common/Modules/Errors/AWSToolError.php new file mode 100644 index 000000000..68f5dc6cb --- /dev/null +++ b/gui/baculum/protected/Common/Modules/Errors/AWSToolError.php @@ -0,0 +1,43 @@ + + * @category Errors + * @package Baculum Common + */ +class AWSToolError extends GenericError { + + const ERROR_AWS_TOOL_DISABLED = 540; + const ERROR_AWS_MISSING_ACCESS_KEY = 541; + const ERROR_AWS_MISSING_SECRET_KEY = 542; + const ERROR_AWS_TOOL_UNABLE_TO_PARSE_OUTPUT = 543; + + const MSG_ERROR_AWS_TOOL_DISABLED = 'AWS tool support is disabled.'; + const MSG_ERROR_AWS_MISSING_ACCESS_KEY = 'Missing access key.'; + const MSG_ERROR_AWS_MISSING_SECRET_KEY = 'Missing secret key.'; + const MSG_ERROR_AWS_TOOL_UNABLE_TO_PARSE_OUTPUT = 'Unable to parse output.'; +} diff --git a/gui/baculum/protected/Common/Modules/Miscellaneous.php b/gui/baculum/protected/Common/Modules/Miscellaneous.php index 35216c5f1..229ad29c3 100644 --- a/gui/baculum/protected/Common/Modules/Miscellaneous.php +++ b/gui/baculum/protected/Common/Modules/Miscellaneous.php @@ -256,6 +256,14 @@ class Miscellaneous extends TModule { return (preg_match('/^[\w\-]+$/', $state) === 1); } + public function isValidLogin($login) { + return (preg_match('/^\w+$/', $login) === 1); + } + + public function isValidSecret($secret) { + return (preg_match('/^[\s\S]+$/u', $secret) === 1); + } + public function isValidInteger($num) { return (preg_match('/^\d+$/', $num) === 1); } @@ -328,6 +336,9 @@ class Miscellaneous extends TModule { return filter_var($email, FILTER_VALIDATE_EMAIL); } + public function isValidURL($url) { + return filter_var($url, FILTER_VALIDATE_URL); + } public function isValidColumn($column) { return (preg_match('/^[\w+.]+$/i', $column) === 1); }