* 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
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.
}
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);
}
?>
--- /dev/null
+<?php
+/*
+ * Bacula(R) - The Network Backup Solution
+ * Baculum - Bacula web interface
+ *
+ * Copyright (C) 2013-2019 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.
+ */
+
+Prado::using('Application.API.Class.ComponentStatusModule');
+
+/**
+ * Module used to get and parse client status output.
+ */
+class StatusClient extends ComponentStatusModule {
+
+ /**
+ * Output types (output sections).
+ */
+ const OUTPUT_TYPE_HEADER = 'header';
+ const OUTPUT_TYPE_RUNNING = 'running';
+ const OUTPUT_TYPE_TERMINATED = 'terminated';
+
+ /**
+ * Get parsed client 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', '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
+ )
+ );
+ }
+}
+?>
* 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
* Bacula(R) is a registered trademark of Kern Sibbald.
*/
+Prado::using('Application.API.Class.Bconsole');
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
+ )
+ );
+ }
}
?>
* 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
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) {
if (count($opts) > 0) {
$opts = array();
}
- } elseif ($output[$i] === 'header:') {
- $header = true;
} else {
$line = $this->parseLine($output[$i]);
if (is_array($line)) {
}
}
}
- 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
+ )
+ );
+ }
}
?>
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;
}
}
}
<!-- component status modules -->
<module id="status_dir" class="Application.API.Class.StatusDirector" />
<module id="status_sd" class="Application.API.Class.StatusStorage" />
+ <module id="status_fd" class="Application.API.Class.StatusClient" />
<!-- misc modules -->
<module id="ls" class="Application.API.Class.Ls" />
</modules>
<url ServiceParameter="API.Config" pattern="api/v1/config/{component_type}/{resource_type}/" parameters.component_type="[a-z]+" parameters.resource_type="[a-zA-Z]+" />
<url ServiceParameter="API.Config" pattern="api/v1/config/{component_type}/{resource_type}/{resource_name}/" parameters.component_type="[a-z]+" parameters.resource_type="[a-zA-Z]+" parameters.resource_name="[a-zA-Z0-9:.\-_ ]+" />
<!-- component status endpoints -->
- <url ServiceParameter="API.ComponentStatus" pattern="api/v1/status/{component}/" parameters.component="[a-z]+" />
+ <url ServiceParameter="API.ComponentStatus" pattern="api/v1/status/{component}/" parameters.component="(director|storage|client)" />