From: Marcin Haba Date: Sun, 28 Jul 2019 17:19:48 +0000 (+0200) Subject: baculum: Add status client API endpoint X-Git-Tag: Release-9.6.0~175 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9df670eb73101041f6488eb231ae85e76cc82dac;p=thirdparty%2Fbacula.git baculum: Add status client API endpoint --- diff --git a/gui/baculum/protected/API/Class/ComponentStatusModule.php b/gui/baculum/protected/API/Class/ComponentStatusModule.php index 8b2e60d796..943599c74e 100644 --- a/gui/baculum/protected/API/Class/ComponentStatusModule.php +++ b/gui/baculum/protected/API/Class/ComponentStatusModule.php @@ -3,7 +3,7 @@ * Bacula(R) - The Network Backup Solution * Baculum - Bacula web interface * - * Copyright (C) 2013-2018 Kern Sibbald + * Copyright (C) 2013-2019 Kern Sibbald * * The main author of Baculum is Marcin Haba. * The original author of Bacula is Kern Sibbald, with contributions @@ -29,11 +29,24 @@ Prado::using('Application.API.Class.APIModule'); abstract class ComponentStatusModule extends APIModule { /** - * Method to get parsed status ready to show in API results. + * Get parsed status. * - * @param array $output array with parsed component status values + * @param string $director director name + * @param string $component_name component name + * @param string $type output type (e.g. header, running, terminated ...etc.) + * @return array ready array parsed component status output */ - abstract public function getStatus(array $output); + abstract public function getStatus($director, $component_name = null, $type = null); + + + /** + * Parse component status. + * + * @param array $output component status output from bconsole + * @param string $type output type (e.g. header, running, terminated ...etc.) + * @return array parsed component status output + */ + abstract public function parseStatus(array $output, $type); /** * Parse single component status line to find key=value pairs. @@ -48,5 +61,13 @@ abstract class ComponentStatusModule extends APIModule { } return $ret; } + + /** + * Validate status output type. + * + * @param string $type output type (e.g. header, running, terminated ...etc.) + * @return boolean true if output type is valid for component, otherwise false + */ + abstract public function isValidOutputType($type); } ?> diff --git a/gui/baculum/protected/API/Class/StatusClient.php b/gui/baculum/protected/API/Class/StatusClient.php new file mode 100644 index 0000000000..e44724dcfa --- /dev/null +++ b/gui/baculum/protected/API/Class/StatusClient.php @@ -0,0 +1,110 @@ + array(), 'error' => 0); + $result = $this->getModule('bconsole')->bconsoleCommand( + $director, + array('.status', 'client="' . $component_name . '"', $type), + Bconsole::PTYPE_API_CMD + ); + if ($result->exitcode === 0) { + $ret['output'] = $this->parseStatus($result->output, $type); + } else { + $ret['output'] = $result->output; + } + $ret['error'] = $result->exitcode; + return $ret; + } + + /** + * Parse .api 2 client status output from bconsole. + * + * @param array $output bconsole status client output + * @param string $type output type (e.g. header, running, terminated ...etc.) + * @return array array with parsed client status values + */ + public function parseStatus(array $output, $type) { + $result = array(); + $line = null; + $opts = array(); + for($i = 0; $i < count($output); $i++) { + if (empty($output[$i])) { + if (count($opts) > 10) { + $result[] = $opts; + } + if (count($opts) > 0) { + $opts = array(); + } + } else { + $line = $this->parseLine($output[$i]); + if (is_array($line)) { + $opts[$line['key']] = $line['value']; + } + } + } + if ($type === self::OUTPUT_TYPE_HEADER) { + $result = array_pop($result); + } + return $result; + } + + /** + * Validate status output type. + * + * @param string $type output type (e.g. header, running, terminated ...etc.) + * @return boolean true if output type is valid for component, otherwise false + */ + public function isValidOutputType($type) { + return in_array( + $type, + array( + self::OUTPUT_TYPE_HEADER, + self::OUTPUT_TYPE_RUNNING, + self::OUTPUT_TYPE_TERMINATED + ) + ); + } +} +?> diff --git a/gui/baculum/protected/API/Class/StatusDirector.php b/gui/baculum/protected/API/Class/StatusDirector.php index b931b16e7c..6d2a77b9f5 100644 --- a/gui/baculum/protected/API/Class/StatusDirector.php +++ b/gui/baculum/protected/API/Class/StatusDirector.php @@ -3,7 +3,7 @@ * Bacula(R) - The Network Backup Solution * Baculum - Bacula web interface * - * Copyright (C) 2013-2018 Kern Sibbald + * Copyright (C) 2013-2019 Kern Sibbald * * The main author of Baculum is Marcin Haba. * The original author of Bacula is Kern Sibbald, with contributions @@ -20,6 +20,7 @@ * Bacula(R) is a registered trademark of Kern Sibbald. */ +Prado::using('Application.API.Class.Bconsole'); Prado::using('Application.API.Class.ComponentStatusModule'); /** @@ -28,41 +29,106 @@ Prado::using('Application.API.Class.ComponentStatusModule'); class StatusDirector extends ComponentStatusModule { /** - * Get director status by raw bconsole status director output. + * Output types (output sections). + */ + const OUTPUT_TYPE_HEADER = 'header'; + const OUTPUT_TYPE_SCHEDULED = 'scheduled'; + const OUTPUT_TYPE_RUNNING = 'running'; + const OUTPUT_TYPE_TERMINATED = 'terminated'; + + + /** + * Get parsed director status. + * + * @param string $director director name + * @param string $component_name component name + * @param string $type output type (e.g. header, running, terminated ...etc.) + * @return array ready array parsed component status output + */ + public function getStatus($director, $component_name = null, $type = null) { + $ret = array('output' => array(), 'error' => 0); + $result = $this->getModule('bconsole')->bconsoleCommand( + $director, + array('status', 'director'), + Bconsole::PTYPE_API_CMD + ); + if ($result->exitcode === 0) { + $ret['output'] = $this->parseStatus($result->output, $type); + if (is_string($type) && key_exists($type, $ret['output'])) { + if ($type === self::OUTPUT_TYPE_HEADER) { + $ret['output'] = array_pop($ret['output'][$type]); + } else { + $ret['output'] = $ret['output'][$type]; + } + } + } else { + $ret['output'] = $result->output; + } + $ret['error'] = $result->exitcode; + return $ret; + } + + /** + * Parse .api 2 director status output from bconsole. * * @param array $output bconsole status director output + * @param string $type output type (e.g. header, running, terminated ...etc.) * @return array array with parsed director status values */ - public function getStatus(array $output) { + public function parseStatus(array $output, $type) { $result = array(); - $section = null; + $type = null; $line = null; - $sections = array('header:', 'running:', 'terminated:'); + $types = array( + self::OUTPUT_TYPE_HEADER . ':', + self::OUTPUT_TYPE_RUNNING . ':', + self::OUTPUT_TYPE_TERMINATED . ':' + ); $opts = array(); for($i = 0; $i < count($output); $i++) { - if (in_array($output[$i], $sections)) { // check if section - $section = rtrim($output[$i], ':'); - } elseif ($section === 'header' && count($opts) == 0 && $output[$i] === '') { + if (in_array($output[$i], $types)) { // check if type + $type = rtrim($output[$i], ':'); + } elseif ($type === self::OUTPUT_TYPE_HEADER && count($opts) == 0 && $output[$i] === '') { /** - * special treating 'scheduled' section because this section + * special treating 'scheduled' type because this type * is missing in the api status dir output. */ - $section = 'scheduled'; - } elseif (!empty($section)) { + $type = self::OUTPUT_TYPE_SCHEDULED; + } elseif (!empty($type)) { $line = $this->parseLine($output[$i]); if (is_array($line)) { // check if line - if (!key_exists($section, $result)) { - $result[$section] = array(); - continue; + if (!key_exists($type, $result)) { + $result[$type] = array(); } $opts[$line['key']] = $line['value']; } elseif (count($opts) > 0) { // dump all parameters - $result[$section][] = $opts; + $result[$type][] = $opts; $opts = array(); } } } + if ($type === self::OUTPUT_TYPE_HEADER) { + $result = array_pop($result); + } return $result; } + + /** + * Validate status output type. + * + * @param string $type output type (e.g. header, running, terminated ...etc.) + * @return boolean true if output type is valid for component, otherwise false + */ + public function isValidOutputType($type) { + return in_array( + $type, + array( + self::OUTPUT_TYPE_HEADER, + self::OUTPUT_TYPE_SCHEDULED, + self::OUTPUT_TYPE_RUNNING, + self::OUTPUT_TYPE_TERMINATED + ) + ); + } } ?> diff --git a/gui/baculum/protected/API/Class/StatusStorage.php b/gui/baculum/protected/API/Class/StatusStorage.php index d3b7580e1d..ebbff12bf3 100644 --- a/gui/baculum/protected/API/Class/StatusStorage.php +++ b/gui/baculum/protected/API/Class/StatusStorage.php @@ -3,7 +3,7 @@ * Bacula(R) - The Network Backup Solution * Baculum - Bacula web interface * - * Copyright (C) 2013-2018 Kern Sibbald + * Copyright (C) 2013-2019 Kern Sibbald * * The main author of Baculum is Marcin Haba. * The original author of Bacula is Kern Sibbald, with contributions @@ -23,21 +23,53 @@ Prado::using('Application.API.Class.ComponentStatusModule'); /** - * Module used to parse and prepare storage status output. + * Module used to get and parse storage status output. */ class StatusStorage extends ComponentStatusModule { /** - * Get director status by raw bconsole status director output. + * Output types (output sections). + */ + const OUTPUT_TYPE_HEADER = 'header'; + const OUTPUT_TYPE_RUNNING = 'running'; + const OUTPUT_TYPE_TERMINATED = 'terminated'; + const OUTPUT_TYPE_DEVICES = 'devices'; + + /** + * Get parsed storage status. + * + * @param string $director director name + * @param string $component_name component name + * @param string $type output type (e.g. header, running, terminated ...etc.) + * @return array ready array parsed component status output + */ + public function getStatus($director, $component_name = null, $type = null) { + $ret = array('output' => array(), 'error' => 0); + $result = $this->getModule('bconsole')->bconsoleCommand( + $director, + array('.status', 'storage="' . $component_name . '"', $type), + Bconsole::PTYPE_API_CMD + ); + if ($result->exitcode === 0) { + $ret['output'] = $this->parseStatus($result->output, $type); + } else { + $ret['output'] = $result->output; + } + $ret['error'] = $result->exitcode; + return $ret; + } + + /** + * Parse .api 2 storage status output from bconsole. * - * @param array $output bconsole status director output + * @param array $output bconsole status storage output + * @param string $type output type (e.g. header, running, terminated ...etc.) * @return array array with parsed storage status values */ - public function getStatus(array $output) { + public function parseStatus(array $output, $type) { $result = array(); $line = null; $opts = array(); - $header = false; for($i = 0; $i < count($output); $i++) { if (empty($output[$i])) { if (count($opts) > 10) { @@ -46,8 +78,6 @@ class StatusStorage extends ComponentStatusModule { if (count($opts) > 0) { $opts = array(); } - } elseif ($output[$i] === 'header:') { - $header = true; } else { $line = $this->parseLine($output[$i]); if (is_array($line)) { @@ -55,11 +85,28 @@ class StatusStorage extends ComponentStatusModule { } } } - if ($header) { - // header is only one so get it without using list + if ($type === self::OUTPUT_TYPE_HEADER) { $result = array_pop($result); } return $result; } + + /** + * Validate status output type. + * + * @param string $type output type (e.g. header, running, terminated ...etc.) + * @return boolean true if output type is valid for component, otherwise false + */ + public function isValidOutputType($type) { + return in_array( + $type, + array( + self::OUTPUT_TYPE_HEADER, + self::OUTPUT_TYPE_RUNNING, + self::OUTPUT_TYPE_TERMINATED, + self::OUTPUT_TYPE_DEVICES + ) + ); + } } ?> diff --git a/gui/baculum/protected/API/Pages/API/ComponentStatus.php b/gui/baculum/protected/API/Pages/API/ComponentStatus.php index c809eaba7c..e7c9c0db42 100644 --- a/gui/baculum/protected/API/Pages/API/ComponentStatus.php +++ b/gui/baculum/protected/API/Pages/API/ComponentStatus.php @@ -28,52 +28,37 @@ Prado::using('Application.API.Class.Bconsole'); class ComponentStatus extends BaculumAPIServer { public function get() { - $status = array(); - $misc = $this->getModule('misc'); $component = $this->Request->contains('component') ? $this->Request['component'] : ''; - $type = $this->Request->contains('type') && $misc->isValidName($this->Request['type']) ? $this->Request['type'] : ''; - + $component_name = $this->Request->contains('name') && $this->getModule('misc')->isValidName($this->Request['name']) ? $this->Request['name'] : null; + $type = null; + $status = null; switch($component) { case 'director': { - $result = $this->getModule('bconsole')->bconsoleCommand( - $this->director, - array('status', 'director'), - Bconsole::PTYPE_API_CMD - ); - if ($result->exitcode === 0) { - $output = $this->getModule('status_dir')->getStatus($result->output); - if ($misc->isValidName($type) && key_exists($type, $output)) { - $this->output = $output[$type]; - } else { - $this->output = $output; - } - } else { - $this->output = $result->output; - } - $this->error = $result->exitcode; + $status = $this->getModule('status_dir'); + $type = $this->Request->contains('type') && $status->isValidOutputType($this->Request['type']) ? $this->Request['type'] : ''; break; } case 'storage': { - $storage = 'storage'; - if (empty($type)) { - $type = 'header'; // default list terminated jobs - } - if ($this->Request->contains('name') && $misc->isValidName($this->Request['name'])) { - $storage .= '="' . $this->Request['name'] . '"'; - } - $result = $this->getModule('bconsole')->bconsoleCommand( - $this->director, - array('.status', $storage, $type), - Bconsole::PTYPE_API_CMD - ); - if ($result->exitcode === 0) { - $this->output = $this->getModule('status_sd')->getStatus($result->output); - } else { - $this->output = $result->output; - } - $this->error = $result->exitcode; + $status = $this->getModule('status_sd'); + $type = $this->Request->contains('type') && $status->isValidOutputType($this->Request['type']) ? $this->Request['type'] : 'header'; break; } + case 'client': { + $status = $this->getModule('status_fd'); + $type = $this->Request->contains('type') && $status->isValidOutputType($this->Request['type']) ? $this->Request['type'] : 'header'; + } + } + if (is_object($status)) { + $ret = $status->getStatus( + $this->director, + $component_name, + $type + ); + $this->output = $ret['output']; + $this->error = $ret['error']; + } else { + $this->output = GenericError::MSG_ERROR_INTERNAL_ERROR; + $this->error = GenericError::ERROR_INTERNAL_ERROR; } } } diff --git a/gui/baculum/protected/API/Pages/config.xml b/gui/baculum/protected/API/Pages/config.xml index 2023d39a76..d20e0d4418 100644 --- a/gui/baculum/protected/API/Pages/config.xml +++ b/gui/baculum/protected/API/Pages/config.xml @@ -38,6 +38,7 @@ + diff --git a/gui/baculum/protected/API/endpoints.xml b/gui/baculum/protected/API/endpoints.xml index e934106c63..45ee61ab1f 100644 --- a/gui/baculum/protected/API/endpoints.xml +++ b/gui/baculum/protected/API/endpoints.xml @@ -90,7 +90,7 @@ - +