From: Marcin Haba Date: Thu, 1 Aug 2019 04:47:30 +0000 (+0200) Subject: baculum: Implement component start/stop/restart actions in API X-Git-Tag: Release-9.6.0~169 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2c6d808fef268fe0e7f5110f3a9811bb55fd6939;p=thirdparty%2Fbacula.git baculum: Implement component start/stop/restart actions in API --- diff --git a/gui/baculum/protected/API/Class/APIConfig.php b/gui/baculum/protected/API/Class/APIConfig.php index 9c51e0a34..ddcd7fda4 100644 --- a/gui/baculum/protected/API/Class/APIConfig.php +++ b/gui/baculum/protected/API/Class/APIConfig.php @@ -3,7 +3,7 @@ * Bacula(R) - The Network Backup Solution * Baculum - Bacula web interface * - * Copyright (C) 2013-2016 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 @@ -53,6 +53,19 @@ class APIConfig extends ConfigFileModule { const JSON_TOOL_FD_TYPE = 'fd'; const JSON_TOOL_BCONS_TYPE = 'bcons'; + /** + * Action types + */ + const ACTION_DIR_START = 'dir_start'; + const ACTION_DIR_STOP = 'dir_stop'; + const ACTION_DIR_RESTART = 'dir_restart'; + const ACTION_SD_START = 'sd_start'; + const ACTION_SD_STOP = 'sd_stop'; + const ACTION_SD_RESTART = 'sd_restart'; + const ACTION_FD_START = 'fd_start'; + const ACTION_FD_STOP = 'fd_stop'; + const ACTION_FD_RESTART = 'fd_restart'; + /** * These options are obligatory for API config. */ @@ -107,18 +120,16 @@ class APIConfig extends ConfigFileModule { * @return boolean true if config valid, otherwise false */ private function validateConfig(array $config = array()) { - $is_valid = $this->isConfigValid($this->required_options, $config, self::CONFIG_FILE_FORMAT, self::CONFIG_FILE_PATH); - return $is_valid; + return $this->isConfigValid($this->required_options, $config, self::CONFIG_FILE_FORMAT, self::CONFIG_FILE_PATH); } private function getJSONToolTypes() { - $types = array( + return array( self::JSON_TOOL_DIR_TYPE, self::JSON_TOOL_SD_TYPE, self::JSON_TOOL_FD_TYPE, self::JSON_TOOL_BCONS_TYPE ); - return $types; } /** @@ -268,4 +279,105 @@ class APIConfig extends ConfigFileModule { } return $tools; } + + /** + * Get action types. + * + * @return array action types + */ + public function getActionTypes() { + return array( + self::ACTION_DIR_START, + self::ACTION_DIR_STOP, + self::ACTION_DIR_RESTART, + self::ACTION_SD_START, + self::ACTION_SD_STOP, + self::ACTION_SD_RESTART, + self::ACTION_FD_START, + self::ACTION_FD_STOP, + self::ACTION_FD_RESTART + ); + } + + /** + * Check if Actions are configured for application. + * + * @return boolean true if Actions are configured, otherwise false + */ + public function isActionsConfigured() { + $config = $this->getConfig(); + return key_exists('actions', $config); + } + + /** + * Check if single action is configured for application. + * + * @return boolean true if single action is configured, otherwise false + */ + public function isActionConfigured($action_type) { + $configured = false; + $config = $this->getActionsConfig(); + return (key_exists($action_type, $config) && !empty($config[$action_type])); + } + + /** + * Check if Actions support is enabled. + * + * @return boolean true if Actions support is enabled, otherwise false + */ + public function isActionsEnabled() { + $enabled = false; + if ($this->isActionsConfigured() === true) { + $config = $this->getConfig(); + $enabled = ($config['actions']['enabled'] == 1); + } + return $enabled; + } + + /** + * Get Actions config parameters. + * + * @return array Actions config parameters + */ + public function getActionsConfig() { + $cfg = array(); + if ($this->isActionsConfigured() === true) { + $config = $this->getConfig(); + $cfg = $config['actions']; + } + return $cfg; + } + + /** + * Get single action command and sudo option. + * + * @param string $action_type action type (dir_start, dir_stop ...etc.) + * @return array command and sudo option state + */ + public function getActionConfig($action_type) { + $action = array('cmd' => '', 'use_sudo' => false); + $actions = $this->getSupportedActions(); + $config = $this->getActionsConfig(); + if (in_array($action_type, $actions) && $this->isActionConfigured($action_type) === true) { + $action['cmd'] = $config[$action_type]; + $action['use_sudo'] = ($config['use_sudo'] == 1); + } + return $action; + } + + /** + * Get supported actions defined in API config. + * + * @return array supported actions + */ + public function getSupportedActions() { + $actions = array(); + $types = $this->getActionTypes(); + for ($i = 0; $i < count($types); $i++) { + if ($this->isActionConfigured($types[$i]) === true) { + array_push($actions, $types[$i]); + } + } + return $actions; + } } diff --git a/gui/baculum/protected/API/Class/BaculumAPIServer.php b/gui/baculum/protected/API/Class/BaculumAPIServer.php index 29c839c98..90e7334cb 100644 --- a/gui/baculum/protected/API/Class/BaculumAPIServer.php +++ b/gui/baculum/protected/API/Class/BaculumAPIServer.php @@ -139,8 +139,8 @@ abstract class BaculumAPIServer extends TPage { if ($is_auth === false) { // Authorization error. header(OAuth2::HEADER_UNAUTHORIZED); - $this->output = AuthorizationError::MSG_ERROR_AUTHORIZATION_TO_API_PROBLEM; - $this->error = AuthorizationError::ERROR_AUTHORIZATION_TO_API_PROBLEM; + $this->output = AuthorizationError::MSG_ERROR_AUTHENTICATION_TO_API_PROBLEM; + $this->error = AuthorizationError::ERROR_AUTHENTICATION_TO_API_PROBLEM; return; } try { diff --git a/gui/baculum/protected/API/Class/ComponentActions.php b/gui/baculum/protected/API/Class/ComponentActions.php new file mode 100644 index 000000000..baaf0d57d --- /dev/null +++ b/gui/baculum/protected/API/Class/ComponentActions.php @@ -0,0 +1,131 @@ +&1"; + + /** + * Get command pattern. + * + * @return string command pattern + */ + private function getCmdPattern() { + // Default command pattern + return self::ACTION_COMMAND_PATTERN; + } + + /** + * Get sudo command. + * + * @param boolean $use_sudo sudo option state + * @return string sudo command + */ + private function getSudo($use_sudo) { + $sudo = ''; + if ($use_sudo === true) { + $sudo = self::SUDO . ' '; + } + return $sudo; + } + + /** + * Execute single action command. + * + * @param string $action_type action type (dir_start, dir_stop ...etc.) + * @return array result with output and exitcode + */ + public function execAction($action_type) { + $result = null; + $output = array(); + $exitcode = -1; + $api_config = $this->getModule('api_config'); + if ($api_config->isActionConfigured($action_type) === true) { + if ($api_config->isActionsEnabled() === true) { + $action = $api_config->getActionConfig($action_type); + $result = $this->execCommand($action['cmd'], $action['use_sudo']); + if ($result->error !== 0) { + $emsg = PHP_EOL . ' Output:' . implode(PHP_EOL, $result->output); + $output = ActionsError::MSG_ERROR_ACTIONS_WRONG_EXITCODE . $emsg; + $exitcode = ActionsError::ERROR_ACTIONS_WRONG_EXITCODE; + $result = $this->prepareResult($output, $exitcode); + } + } else { + $output = ActionsError::MSG_ERROR_ACTIONS_DISABLED; + $exitcode = ActionsError::ERROR_ACTIONS_DISABLED; + $result = $this->prepareResult($output, $exitcode); + } + } else { + $output = ActionsError::MSG_ERROR_ACTIONS_NOT_CONFIGURED; + $exitcode = ActionsError::ERROR_ACTIONS_NOT_CONFIGURED; + $result = $this->prepareResult($output, $exitcode); + } + return $result; + } + + /** + * Execute action command. + * + * @param string $bin command + * @param boolean $use_sudo use sudo + */ + public function execCommand($bin, $use_sudo) { + $sudo = $this->getSudo($use_sudo); + $cmd_pattern = $this->getCmdPattern(); + $cmd = sprintf($cmd_pattern, $sudo, $bin); + exec($cmd, $output, $exitcode); + $this->getModule('logging')->log($cmd, $output, Logging::CATEGORY_EXECUTE, __FILE__, __LINE__); + $result = $this->prepareResult($output, $exitcode); + return $result; + } + + /** + * Prepare action command result. + * + * @param array $output output from command execution + * @param integer $exitcode command exit code + * @return array result with output and exitcode + */ + public function prepareResult($output, $exitcode) { + $result = (object)array( + 'output' => $output, + 'error' => $exitcode + ); + return $result; + } + +} +?> diff --git a/gui/baculum/protected/API/JavaScript/misc.js b/gui/baculum/protected/API/JavaScript/misc.js index 8c7b21c69..22c9aa5d3 100644 --- a/gui/baculum/protected/API/JavaScript/misc.js +++ b/gui/baculum/protected/API/JavaScript/misc.js @@ -19,7 +19,8 @@ var OAuth2Scopes = [ 'filesets', 'schedules', 'config', - 'status' + 'status', + 'actions' ]; var set_scopes = function(field_id) { document.getElementById(field_id).value = OAuth2Scopes.join(' '); diff --git a/gui/baculum/protected/API/Lang/en/messages.mo b/gui/baculum/protected/API/Lang/en/messages.mo index f5f967004..5f2c944a5 100644 Binary files a/gui/baculum/protected/API/Lang/en/messages.mo and b/gui/baculum/protected/API/Lang/en/messages.mo differ diff --git a/gui/baculum/protected/API/Lang/en/messages.po b/gui/baculum/protected/API/Lang/en/messages.po index 60a13bc46..59faa6de5 100644 --- a/gui/baculum/protected/API/Lang/en/messages.po +++ b/gui/baculum/protected/API/Lang/en/messages.po @@ -194,18 +194,12 @@ msgstr "Config API" msgid "Error" msgstr "Error" -msgid "Authorization" -msgstr "Authorization" - msgid "Finish" msgstr "Finish" msgid "Do you want to setup and share the Bacula configuration interface to configure Bacula components via this API instance?" msgstr "Do you want to setup and share the Bacula configuration interface to configure Bacula components via this API instance?" -msgid "Step 5 - authorization to API" -msgstr "Step 5 - authorization to API" - msgid "Administration login:" msgstr "Administration login:" @@ -242,17 +236,11 @@ msgstr "Database file path (SQLite only):" msgid "Use sudo for bconsole requests:" msgstr "Use sudo for bconsole requests:" -msgid "Authorization to Baculum REST API" -msgstr "Authorization to Baculum REST API" - msgid "Save" msgstr "Save" -msgid "Authorization type:" -msgstr "Authorization type:" - -msgid "Step 6 - Finish" -msgstr "Step 6 - Finish" +msgid "Step 7 - Finish" +msgstr "Step 7 - Finish" msgid "Use sudo for Bacula JSON tools:" msgstr "Use sudo for Bacula JSON tools:" @@ -439,3 +427,87 @@ msgstr "In this directory Baculum API saves temporarily Bacula configuration fil msgid "Version:" msgstr "Version:" + +msgid "Authentication" +msgstr "Authentication" + +msgid "Authentication to Baculum REST API" +msgstr "Authentication to Baculum REST API" + +msgid "Authentication type:" +msgstr "Authentication type:" + +msgid "Step 6 - authentication to API" +msgstr "Step 6 - authentication to API" + +msgid "Actions" +msgstr "Actions" + +msgid "Start" +msgstr "Start" + +msgid "Stop" +msgstr "Stop" + +msgid "Restart" +msgstr "Restart" + +msgid "Director start command:" +msgstr "Director start command:" + +msgid "Director stop command:" +msgstr "Director stop command:" + +msgid "Director restart command:" +msgstr "Director restart command:" + +msgid "Storage Daemon start command:" +msgstr "Storage Daemon start command:" + +msgid "Storage Daemon stop command:" +msgstr "Storage Daemon stop command:" + +msgid "Storage Daemon restart command:" +msgstr "Storage Daemon restart command:" + +msgid "File Daemon/Client start command:" +msgstr "File Daemon/Client start command:" + +msgid "File Daemon/Client stop command:" +msgstr "File Daemon/Client stop command:" + +msgid "File Daemon/Client restart command:" +msgstr "File Daemon/Client restart command:" + +msgid "Do you want to setup start, stop and restart actions for Bacula components? If you define them, there will be possible to call these actions via API interface and by Baculum Web as well." +msgstr "Do you want to setup start, stop and restart actions for Bacula components? If you define them, there will be possible to call these actions via API interface and by Baculum Web as well." + +msgid "Sudo configuration" +msgstr "Sudo configuration" + +msgid "Example sudo configuration for Apache web server user (RHEL, CentOS and others):" +msgstr "Example sudo configuration for Apache web server user (RHEL, CentOS and others):" + +msgid "Example sudo configuration for Lighttpd web server user (RHEL, CentOS and others):" +msgstr "Example sudo configuration for Lighttpd web server user (RHEL, CentOS and others):" + +msgid "Example sudo configuration for Apache and Lighttpd web servers user (Debian, Ubuntu and others):" +msgstr "Example sudo configuration for Apache and Lighttpd web servers user (Debian, Ubuntu and others):" + +msgid "Get sudo configuration" +msgstr "Get sudo configuration" + +msgid "Please copy appropriate sudo configuration and put it to a new sudoers.d file for example /etc/sudoers.d/baculum-api" +msgstr "Please copy appropriate sudo configuration and put it to a new sudoers.d file for example /etc/sudoers.d/baculum-api" + +msgid "Step 5 - enable actions for components" +msgstr "Step 5 - enable actions for components" + +msgid "Directory path for new config files:" +msgstr "Directory path for new config files:" + +msgid "Use sudo for actions:" +msgstr "Use sudo for actions:" + +msgid "Actions setting:" +msgstr "Actions setting:" diff --git a/gui/baculum/protected/API/Lang/pl/messages.mo b/gui/baculum/protected/API/Lang/pl/messages.mo index b8375ed65..631790be8 100644 Binary files a/gui/baculum/protected/API/Lang/pl/messages.mo and b/gui/baculum/protected/API/Lang/pl/messages.mo differ diff --git a/gui/baculum/protected/API/Lang/pl/messages.po b/gui/baculum/protected/API/Lang/pl/messages.po index 2496aa752..dd1facc3d 100644 --- a/gui/baculum/protected/API/Lang/pl/messages.po +++ b/gui/baculum/protected/API/Lang/pl/messages.po @@ -194,18 +194,12 @@ msgstr "Config API" msgid "Error" msgstr "Błąd" -msgid "Authorization" -msgstr "Autoryzacja" - msgid "Finish" msgstr "Koniec" msgid "Do you want to setup and share the Bacula configuration interface to configure Bacula components via this API instance?" msgstr "Czy chcesz skonfigurować i udostępnić interfejs konfiguracyjny Bacula do konfiguracji komponentów Bacula poprzez tą instancję API?" -msgid "Step 5 - authorization to API" -msgstr "Krok 5 - autoryzacja do API" - msgid "Administration login:" msgstr "Login administratora:" @@ -242,17 +236,11 @@ msgstr "Lokalizacja pliku DB (tylko SQLite):" msgid "Use sudo for bconsole requests:" msgstr "Użyj sudo dla zapytań bconsole:" -msgid "Authorization to Baculum REST API" -msgstr "Autoryzacja do Baculum REST API" - msgid "Save" msgstr "Zapisz" -msgid "Authorization type:" -msgstr "Typ autoryzacji:" - -msgid "Step 6 - Finish" -msgstr "Krok 6 - Koniec" +msgid "Step 7 - Finish" +msgstr "Krok 7 - Koniec" msgid "Use sudo for Bacula JSON tools:" msgstr "Użyj sudo dla narzędzi JSON Bacula." @@ -439,3 +427,87 @@ msgstr "W tym katalogu Baculum API tymczasowo zapisuje pliki konfiguracyjne Bacu msgid "Version:" msgstr "Wersja:" + +msgid "Authentication" +msgstr "Uwierzytelnianie" + +msgid "Authentication to Baculum REST API" +msgstr "Uwierzytelnianie do Baculum REST API" + +msgid "Authentication type:" +msgstr "Typ uwierzytelniania:" + +msgid "Step 6 - authentication to API" +msgstr "Krok 6 - uwierzytelnianie do API" + +msgid "Actions" +msgstr "Actions" + +msgid "Start" +msgstr "Start" + +msgid "Stop" +msgstr "Stop" + +msgid "Restart" +msgstr "Restart" + +msgid "Director start command:" +msgstr "Komenda uruchomenia Director:" + +msgid "Director stop command:" +msgstr "Komenda zatrzymania Director:" + +msgid "Director restart command:" +msgstr "Komenda restartu Director:" + +msgid "Storage Daemon start command:" +msgstr "Komenda uruchomienia Storage Daemon:" + +msgid "Storage Daemon stop command:" +msgstr "Komenda zatrzymania Storage Daemon:" + +msgid "Storage Daemon restart command:" +msgstr "Komenda restartu Storage Daemon:" + +msgid "File Daemon/Client start command:" +msgstr "Komenda uruchomienia klienta:" + +msgid "File Daemon/Client stop command:" +msgstr "Komenda zatrzymania klienta:" + +msgid "File Daemon/Client restart command:" +msgstr "Komenda restartu klienta:" + +msgid "Do you want to setup start, stop and restart actions for Bacula components? If you define them, there will be possible to call these actions via API interface and by Baculum Web as well." +msgstr "Czy chcesz skonfigurować akcje uruchomienia, zatrzymania i restartu komponentów Bacula? Jeśli zdefiniujesz je, wtedy będzie możliwe wykonywanie tych akcji poprzez interfejs API i również przez Baculum Web." + +msgid "Sudo configuration" +msgstr "Konfiguracja sudo" + +msgid "Example sudo configuration for Apache web server user (RHEL, CentOS and others):" +msgstr "Przykładowa konfiguracja sudo dla użytkownika serwera web Apache (RHEL, CentOS i inne):" + +msgid "Example sudo configuration for Lighttpd web server user (RHEL, CentOS and others):" +msgstr "Przykładowa konfiguracja sudo dla użytkownika serwera web Lighttpd (RHEL, CentOS i inne):" + +msgid "Example sudo configuration for Apache and Lighttpd web servers user (Debian, Ubuntu and others):" +msgstr "Przykładowa konfiguracja sudo dla użytkownika serwerów web Apache i Lighttpd (Debian, Ubuntu i inne):" + +msgid "Get sudo configuration" +msgstr "Weź konfigurację sudo" + +msgid "Please copy appropriate sudo configuration and put it to a new sudoers.d file for example /etc/sudoers.d/baculum-api" +msgstr "Proszę skopiować odpowiednią konfigurację sudo i wpisać ją do nowego pliku sudoers.d na przykład /etc/sudoers.d/baculum-api" + +msgid "Step 5 - enable actions for components" +msgstr "Krok 5 - włącz akcje dla komponentów" + +msgid "Directory path for new config files:" +msgstr "Lokalizacja katalogu na nowe pliki konfiguracyjne:" + +msgid "Use sudo for actions:" +msgstr "Użyj sudo dla akcji:" + +msgid "Actions setting:" +msgstr "Ustawienie akcji:" diff --git a/gui/baculum/protected/API/Lang/pt/messages.mo b/gui/baculum/protected/API/Lang/pt/messages.mo index 395b4cbf9..e9d2ebef5 100644 Binary files a/gui/baculum/protected/API/Lang/pt/messages.mo and b/gui/baculum/protected/API/Lang/pt/messages.mo differ diff --git a/gui/baculum/protected/API/Lang/pt/messages.po b/gui/baculum/protected/API/Lang/pt/messages.po index 5ec37453d..aa0c80194 100644 --- a/gui/baculum/protected/API/Lang/pt/messages.po +++ b/gui/baculum/protected/API/Lang/pt/messages.po @@ -194,18 +194,12 @@ msgstr "Configurar" msgid "Error" msgstr "Erro" -msgid "Authorization" -msgstr "Autorização" - msgid "Finish" msgstr "Finalizar" msgid "Do you want to setup and share the Bacula configuration interface to configure Bacula components via this API instance?" msgstr "Deseja configurar e compartilhar a interface de configuração do Bacula para configurar os recursos através desta instância da API?" -msgid "Step 5 - authorization to API" -msgstr "Passo 5 - Autorização da API" - msgid "Administration login:" msgstr "Usuário administrador:" @@ -242,17 +236,11 @@ msgstr "Caminho para o banco de dados (SQLite somente):" msgid "Use sudo for bconsole requests:" msgstr "Utilizar sudo para executar bconsole:" -msgid "Authorization to Baculum REST API" -msgstr "Autorização para a API REST do Baculum" - msgid "Save" msgstr "Salvar" -msgid "Authorization type:" -msgstr "Tipo de autorização:" - -msgid "Step 6 - Finish" -msgstr "Passo 6 - Finalizar" +msgid "Step 7 - Finish" +msgstr "Passo 7 - Finalizar" msgid "Use sudo for Bacula JSON tools:" msgstr "Utilizar o sudo para os utilitários JSON:" @@ -439,3 +427,87 @@ msgstr "In this directory Baculum API saves temporarily Bacula configuration fil msgid "Version:" msgstr "Version:" + +msgid "Authentication" +msgstr "Authentication" + +msgid "Authentication to Baculum REST API" +msgstr "Authentication to Baculum REST API" + +msgid "Authentication type:" +msgstr "Authentication type:" + +msgid "Step 6 - authentication to API" +msgstr "Step 6 - authentication to API" + +msgid "Actions" +msgstr "Actions" + +msgid "Start" +msgstr "Start" + +msgid "Stop" +msgstr "Stop" + +msgid "Restart" +msgstr "Restart" + +msgid "Director start command:" +msgstr "Director start command:" + +msgid "Director stop command:" +msgstr "Director stop command:" + +msgid "Director restart command:" +msgstr "Director restart command:" + +msgid "Storage Daemon start command:" +msgstr "Storage Daemon start command:" + +msgid "Storage Daemon stop command:" +msgstr "Storage Daemon stop command:" + +msgid "Storage Daemon restart command:" +msgstr "Storage Daemon restart command:" + +msgid "File Daemon/Client start command:" +msgstr "File Daemon/Client start command:" + +msgid "File Daemon/Client stop command:" +msgstr "File Daemon/Client stop command:" + +msgid "File Daemon/Client restart command:" +msgstr "File Daemon/Client restart command:" + +msgid "Do you want to setup start, stop and restart actions for Bacula components? If you define them, there will be possible to call these actions via API interface and by Baculum Web as well." +msgstr "Do you want to setup start, stop and restart actions for Bacula components? If you define them, there will be possible to call these actions via API interface and by Baculum Web as well." + +msgid "Sudo configuration" +msgstr "Sudo configuration" + +msgid "Example sudo configuration for Apache web server user (RHEL, CentOS and others):" +msgstr "Example sudo configuration for Apache web server user (RHEL, CentOS and others):" + +msgid "Example sudo configuration for Lighttpd web server user (RHEL, CentOS and others):" +msgstr "Example sudo configuration for Lighttpd web server user (RHEL, CentOS and others):" + +msgid "Example sudo configuration for Apache and Lighttpd web servers user (Debian, Ubuntu and others):" +msgstr "Example sudo configuration for Apache and Lighttpd web servers user (Debian, Ubuntu and others):" + +msgid "Get sudo configuration" +msgstr "Get sudo configuration" + +msgid "Please copy appropriate sudo configuration and put it to a new sudoers.d file for example /etc/sudoers.d/baculum-api" +msgstr "Please copy appropriate sudo configuration and put it to a new sudoers.d file for example /etc/sudoers.d/baculum-api" + +msgid "Step 5 - enable actions for components" +msgstr "Step 5 - enable actions for components" + +msgid "Directory path for new config files:" +msgstr "Directory path for new config files:" + +msgid "Use sudo for actions:" +msgstr "Use sudo for actions:" + +msgid "Actions setting:" +msgstr "Actions setting:" diff --git a/gui/baculum/protected/API/Pages/API/Actions.php b/gui/baculum/protected/API/Pages/API/Actions.php new file mode 100644 index 000000000..34db5be7f --- /dev/null +++ b/gui/baculum/protected/API/Pages/API/Actions.php @@ -0,0 +1,77 @@ +Request->contains('component') ? $this->Request['component'] : ''; + $action = $this->Request->contains('action') ? $this->Request['action'] : ''; + $action_type = null; + + switch ($component) { + case 'director': + if ($action === 'start') { + $action_type = APIConfig::ACTION_DIR_START; + } elseif ($action === 'stop') { + $action_type = APIConfig::ACTION_DIR_STOP; + } elseif ($action === 'restart') { + $action_type = APIConfig::ACTION_DIR_RESTART; + } + break; + case 'storage': + if ($action === 'start') { + $action_type = APIConfig::ACTION_SD_START; + } elseif ($action === 'stop') { + $action_type = APIConfig::ACTION_SD_STOP; + } elseif ($action === 'restart') { + $action_type = APIConfig::ACTION_SD_RESTART; + } + break; + case 'client': + if ($action === 'start') { + $action_type = APIConfig::ACTION_FD_START; + } elseif ($action === 'stop') { + $action_type = APIConfig::ACTION_FD_STOP; + } elseif ($action === 'restart') { + $action_type = APIConfig::ACTION_FD_RESTART; + } + break; + } + + if (is_string($action_type)) { + $result = $this->getModule('comp_actions')->execAction($action_type); + if ($result->error === 0) { + $this->output = ActionsError::MSG_ERROR_NO_ERRORS; + $this->error = ActionsError::ERROR_NO_ERRORS; + } else { + $this->output = $result->output; + $this->error = $result->error; + } + } else { + $this->output = ActionsError::MSG_ERROR_ACTIONS_ACTION_DOES_NOT_EXIST; + $this->error = ActionsError::ERROR_ACTIONS_ACTION_DOES_NOT_EXIST; + } + } +} +?> diff --git a/gui/baculum/protected/API/Pages/Panel/APIInstallWizard.page b/gui/baculum/protected/API/Pages/Panel/APIInstallWizard.page index 8a86a2d9d..13af87270 100644 --- a/gui/baculum/protected/API/Pages/Panel/APIInstallWizard.page +++ b/gui/baculum/protected/API/Pages/Panel/APIInstallWizard.page @@ -26,9 +26,12 @@
-
+
-
+
+
+
+
<%=$this->Parent->ActiveStep->Title%>
@@ -425,7 +428,253 @@
- + +

<%[ Do you want to setup start, stop and restart actions for Bacula components? If you define them, there will be possible to call these actions via API interface and by Baculum Web as well. ]%>

+
+ +
+
+ +
+
+
+
+ <%[ General configuration ]%> + +
+
+ Director +
+
+
+
+ +
+
+ + + actions_hide_test_results('<%=$this->TestDirStartActionCommand->CommandParameter%>'); + $('#actions_test_result_dir_start .action_test_loader').show(); + + + $('#actions_test_result_dir_start .action_test_loader').hide(); + + +
+ + + + + + +
+
+
+
+ +
+
+ + + actions_hide_test_results('<%=$this->TestDirStopActionCommand->CommandParameter%>'); + $('#actions_test_result_dir_stop .action_test_loader').show(); + + + $('#actions_test_result_dir_stop .action_test_loader').hide(); + + +
+ + + + + + +
+
+
+
+ +
+
+ + + actions_hide_test_results('<%=$this->TestDirRestartActionCommand->CommandParameter%>'); + $('#actions_test_result_dir_restart .action_test_loader').show(); + + + $('#actions_test_result_dir_restart .action_test_loader').hide(); + + +
+ + + + + + +
+
+
+
+ Storage Daemon +
+
+
+
+ +
+
+ + + actions_hide_test_results('<%=$this->TestSdStartActionCommand->CommandParameter%>'); + $('#actions_test_result_sd_start .action_test_loader').show(); + + + $('#actions_test_result_sd_start .action_test_loader').hide(); + + +
+ + + + + + +
+
+
+
+ +
+
+ + + actions_hide_test_results('<%=$this->TestSdStopActionCommand->CommandParameter%>'); + $('#actions_test_result_sd_stop .action_test_loader').show(); + + + $('#actions_test_result_sd_stop .action_test_loader').hide(); + + +
+ + + + + + +
+
+
+
+ +
+
+ + + actions_hide_test_results('<%=$this->TestSdRestartActionCommand->CommandParameter%>'); + $('#actions_test_result_sd_restart .action_test_loader').show(); + + + $('#actions_test_result_sd_restart .action_test_loader').hide(); + + +
+ + + + + + +
+
+
+
+ File Daemon/Client +
+
+
+
+ +
+
+ + + actions_hide_test_results('<%=$this->TestFdStartActionCommand->CommandParameter%>'); + $('#actions_test_result_fd_start .action_test_loader').show(); + + + $('#actions_test_result_fd_start .action_test_loader').hide(); + + +
+ + + + + + +
+
+
+
+ +
+
+ + + actions_hide_test_results('<%=$this->TestFdStopActionCommand->CommandParameter%>'); + $('#actions_test_result_fd_stop .action_test_loader').show(); + + + $('#actions_test_result_fd_stop .action_test_loader').hide(); + + +
+ + + + + + +
+
+
+
+ +
+
+ + + actions_hide_test_results('<%=$this->TestFdRestartActionCommand->CommandParameter%>'); + $('#actions_test_result_fd_restart .action_test_loader').show(); + + + $('#actions_test_result_fd_restart .action_test_loader').hide(); + + +
+ + + + + + +
+
+
+
+
+
+
- +
<%[ Catalog API ]%>
@@ -802,9 +1051,60 @@
- <%[ Authorization to Baculum REST API ]%> + <%[ Actions ]%> +
+
+
<%[ Use sudo for actions: ]%>
+
<%=($this->ActionsUseSudo->Checked === true) ? 'yes' : 'no'%>
+
+
+
<%[ Director start command: ]%>
+
<%=$this->DirStartAction->Text%>
+
+
+
<%[ Director stop command: ]%>
+
<%=$this->DirStopAction->Text%>
+
+
+
<%[ Director restart command: ]%>
+
<%=$this->DirRestartAction->Text%>
+
+
+
<%[ Storage Daemon start command: ]%>
+
<%=$this->SdStartAction->Text%>
+
+
+
<%[ Storage Daemon stop command: ]%>
+
<%=$this->SdStopAction->Text%>
+
+
+
<%[ Storage Daemon restart command: ]%>
+
<%=$this->SdRestartAction->Text%>
+
+
+
<%[ File Daemon/Client start command: ]%>
+
<%=$this->FdStartAction->Text%>
+
+
+
<%[ File Daemon/Client stop command: ]%>
+
<%=$this->FdStopAction->Text%>
+
+
+
<%[ File Daemon/Client restart command: ]%>
+
<%=$this->FdRestartAction->Text%>
+
+
+
+
+
<%[ Actions setting: ]%>
+
<%[ Disabled ]%>
+
+
+
+
+ <%[ Authentication to Baculum REST API ]%>
-
<%[ Authorization type: ]%>
+
<%[ Authentication type: ]%>
<%=$this->AuthBasic->Checked ? 'HTTP Basic' : ''%> <%=$this->AuthOAuth2->Checked ? 'OAuth2' : ''%> @@ -849,6 +1149,21 @@
+ +

<%[ Please copy appropriate sudo configuration and put it to a new sudoers.d file for example /etc/sudoers.d/baculum-api ]%>

+

<%[ Example sudo configuration for Apache web server user (RHEL, CentOS and others): ]%>

+

+	

<%[ Example sudo configuration for Lighttpd web server user (RHEL, CentOS and others): ]%>

+

+	

<%[ Example sudo configuration for Apache and Lighttpd web servers user (Debian, Ubuntu and others): ]%>

+

+
diff --git a/gui/baculum/protected/API/Pages/Panel/APIInstallWizard.php b/gui/baculum/protected/API/Pages/Panel/APIInstallWizard.php index f1cd2947b..7a507e21c 100644 --- a/gui/baculum/protected/API/Pages/Panel/APIInstallWizard.php +++ b/gui/baculum/protected/API/Pages/Panel/APIInstallWizard.php @@ -53,6 +53,16 @@ class APIInstallWizard extends BaculumAPIPage { const DEFAULT_FD_CONF = '/etc/bacula/bacula-fd.conf'; const DEFAULT_BBCONJSON_BIN = '/usr/sbin/bbconsjson'; + const DEFAULT_ACTION_DIR_START = '/usr/bin/systemctl start bacula-dir'; + const DEFAULT_ACTION_DIR_STOP = '/usr/bin/systemctl stop bacula-dir'; + const DEFAULT_ACTION_DIR_RESTART = '/usr/bin/systemctl restart bacula-dir'; + const DEFAULT_ACTION_SD_START = '/usr/bin/systemctl start bacula-sd'; + const DEFAULT_ACTION_SD_STOP = '/usr/bin/systemctl stop bacula-sd'; + const DEFAULT_ACTION_SD_RESTART = '/usr/bin/systemctl restart bacula-sd'; + const DEFAULT_ACTION_FD_START = '/usr/bin/systemctl start bacula-fd'; + const DEFAULT_ACTION_FD_STOP = '/usr/bin/systemctl stop bacula-fd'; + const DEFAULT_ACTION_FD_RESTART = '/usr/bin/systemctl restart bacula-fd'; + public function onPreInit($param) { parent::onPreInit($param); if (isset($_SESSION['language'])) { @@ -89,9 +99,21 @@ class APIInstallWizard extends BaculumAPIPage { $this->FdCfgPath->Text = self::DEFAULT_FD_CONF; $this->BBconsJSONPath->Text = self::DEFAULT_BBCONJSON_BIN; $this->BconsCfgPath->Text = self::DEFAULT_BCONSOLE_CONF; + + $this->DirStartAction->Text = self::DEFAULT_ACTION_DIR_START; + $this->DirStopAction->Text = self::DEFAULT_ACTION_DIR_STOP; + $this->DirRestartAction->Text = self::DEFAULT_ACTION_DIR_RESTART; + $this->SdStartAction->Text = self::DEFAULT_ACTION_SD_START; + $this->SdStopAction->Text = self::DEFAULT_ACTION_SD_STOP; + $this->SdRestartAction->Text = self::DEFAULT_ACTION_SD_RESTART; + $this->FdStartAction->Text = self::DEFAULT_ACTION_FD_START; + $this->FdStopAction->Text = self::DEFAULT_ACTION_FD_STOP; + $this->FdRestartAction->Text = self::DEFAULT_ACTION_FD_RESTART; + $this->DatabaseNo->Checked = true; $this->ConsoleNo->Checked = true; $this->ConfigNo->Checked = true; + $this->ActionsNo->Checked = true; } else { // Database param settings if ($this->config['db']['enabled'] == 1) { @@ -122,8 +144,10 @@ class APIInstallWizard extends BaculumAPIPage { $this->BconsoleConfigPath->Text = $this->config['bconsole']['cfg_path']; $this->UseSudo->Checked = $this->getPage()->config['bconsole']['use_sudo'] == 1; + $api_config = $this->getModule('api_config'); + // JSONTools param settings - if ($this->config['jsontools']['enabled'] == 1) { + if ($api_config->isJSONToolsEnabled() === true) { $this->ConfigYes->Checked = true; $this->ConfigNo->Checked = false; } else { @@ -141,6 +165,41 @@ class APIInstallWizard extends BaculumAPIPage { $this->BBconsJSONPath->Text = $this->config['jsontools']['bbconsjson_path']; $this->BconsCfgPath->Text = $this->config['jsontools']['bcons_cfg_path']; + if ($api_config->isActionsConfigured()) { + // Action params + if ($api_config->isActionsEnabled() === true) { + $this->ActionsYes->Checked = true; + $this->ActionsNo->Checked = false; + } else { + $this->ActionsYes->Checked = false; + $this->ActionsNo->Checked = true; + } + + $this->ActionsUseSudo->Checked = ($this->config['actions']['use_sudo'] == 1); + $this->DirStartAction->Text = $this->config['actions']['dir_start']; + $this->DirStopAction->Text = $this->config['actions']['dir_stop']; + $this->DirRestartAction->Text = $this->config['actions']['dir_restart']; + $this->SdStartAction->Text = $this->config['actions']['sd_start']; + $this->SdStopAction->Text = $this->config['actions']['sd_stop']; + $this->SdRestartAction->Text = $this->config['actions']['sd_restart']; + $this->FdStartAction->Text = $this->config['actions']['fd_start']; + $this->FdStopAction->Text = $this->config['actions']['fd_stop']; + $this->FdRestartAction->Text = $this->config['actions']['fd_restart']; + } else { + $this->ActionsYes->Checked = false; + $this->ActionsNo->Checked = true; + $this->ActionsUseSudo->Checked = false; + $this->DirStartAction->Text = self::DEFAULT_ACTION_DIR_START; + $this->DirStopAction->Text = self::DEFAULT_ACTION_DIR_STOP; + $this->DirRestartAction->Text = self::DEFAULT_ACTION_DIR_RESTART; + $this->SdStartAction->Text = self::DEFAULT_ACTION_SD_START; + $this->SdStopAction->Text = self::DEFAULT_ACTION_SD_STOP; + $this->SdRestartAction->Text = self::DEFAULT_ACTION_SD_RESTART; + $this->FdStartAction->Text = self::DEFAULT_ACTION_FD_START; + $this->FdStopAction->Text = self::DEFAULT_ACTION_FD_STOP; + $this->FdRestartAction->Text = self::DEFAULT_ACTION_FD_RESTART; + } + if ($this->config['api']['auth_type'] === 'basic') { // API basic auth data $this->AuthBasic->Checked = true; @@ -169,7 +228,8 @@ class APIInstallWizard extends BaculumAPIPage { 'api' => array(), 'db' => array(), 'bconsole' => array(), - 'jsontools' => array() + 'jsontools' => array(), + 'actions' => array() ); if ($this->AuthBasic->Checked) { $cfg_data['api']['auth_type'] = 'basic'; @@ -201,6 +261,17 @@ class APIInstallWizard extends BaculumAPIPage { $cfg_data['jsontools']['fd_cfg_path'] = $this->FdCfgPath->Text; $cfg_data['jsontools']['bbconsjson_path'] = $this->BBconsJSONPath->Text; $cfg_data['jsontools']['bcons_cfg_path'] = $this->BconsCfgPath->Text; + $cfg_data['actions']['enabled'] = (integer)($this->ActionsYes->Checked === true); + $cfg_data['actions']['use_sudo'] = (integer)($this->ActionsUseSudo->Checked === true); + $cfg_data['actions']['dir_start'] = $this->DirStartAction->Text; + $cfg_data['actions']['dir_stop'] = $this->DirStopAction->Text; + $cfg_data['actions']['dir_restart'] = $this->DirRestartAction->Text; + $cfg_data['actions']['sd_start'] = $this->SdStartAction->Text; + $cfg_data['actions']['sd_stop'] = $this->SdStopAction->Text; + $cfg_data['actions']['sd_restart'] = $this->SdRestartAction->Text; + $cfg_data['actions']['fd_start'] = $this->FdStartAction->Text; + $cfg_data['actions']['fd_stop'] = $this->FdStopAction->Text; + $cfg_data['actions']['fd_restart'] = $this->FdRestartAction->Text; $ret = $this->getModule('api_config')->setConfig($cfg_data); if ($ret) { @@ -426,5 +497,23 @@ class APIInstallWizard extends BaculumAPIPage { } $param->setIsValid($valid); } + + public function testExecActionCommand($sender, $param) { + $action = $param->CommandParameter; + $cmd = ''; + switch ($action) { + case 'dir_start': $cmd = $this->DirStartAction->Text; break; + case 'dir_stop': $cmd = $this->DirStopAction->Text; break; + case 'dir_restart': $cmd = $this->DirRestartAction->Text; break; + case 'sd_start': $cmd = $this->SdStartAction->Text; break; + case 'sd_stop': $cmd = $this->SdStopAction->Text; break; + case 'sd_restart': $cmd = $this->SdRestartAction->Text; break; + case 'fd_start': $cmd = $this->FdStartAction->Text; break; + case 'fd_stop': $cmd = $this->FdStopAction->Text; break; + case 'fd_restart': $cmd = $this->FdRestartAction->Text; break; + }; + $result = $this->getModule('comp_actions')->execCommand($cmd, $this->ActionsUseSudo->Checked); + $this->getCallbackClient()->callClientFunction('set_action_command_output', array($action, (array)$result)); + } } ?> diff --git a/gui/baculum/protected/API/Pages/config.xml b/gui/baculum/protected/API/Pages/config.xml index d20e0d441..65e2c34a2 100644 --- a/gui/baculum/protected/API/Pages/config.xml +++ b/gui/baculum/protected/API/Pages/config.xml @@ -39,6 +39,8 @@ + + diff --git a/gui/baculum/protected/API/endpoints.xml b/gui/baculum/protected/API/endpoints.xml index 45ee61ab1..d1cc5721b 100644 --- a/gui/baculum/protected/API/endpoints.xml +++ b/gui/baculum/protected/API/endpoints.xml @@ -91,6 +91,8 @@ + + diff --git a/gui/baculum/protected/Common/Class/Errors.php b/gui/baculum/protected/Common/Class/Errors.php index 53d2f4ee2..de9a5a9d5 100644 --- a/gui/baculum/protected/Common/Class/Errors.php +++ b/gui/baculum/protected/Common/Class/Errors.php @@ -53,10 +53,10 @@ class BconsoleError extends GenericError { class AuthorizationError extends GenericError { - const ERROR_AUTHORIZATION_TO_API_PROBLEM = 6; + const ERROR_AUTHENTICATION_TO_API_PROBLEM = 6; const ERROR_ACCESS_ATTEMPT_TO_NOT_ALLOWED_RESOURCE = 7; - const MSG_ERROR_AUTHORIZATION_TO_API_PROBLEM = 'Problem with authorization to Baculum API.'; + const MSG_ERROR_AUTHENTICATION_TO_API_PROBLEM = 'Problem with authentication to Baculum API.'; const MSG_ERROR_ACCESS_ATTEMPT_TO_NOT_ALLOWED_RESOURCE = 'Access attempt to not allowed resource. Permission denied.'; } @@ -177,4 +177,18 @@ class ConnectionError extends GenericError { const MSG_ERROR_CONNECTION_TO_HOST_PROBLEM = 'Problem with connection to remote host.'; } + +class ActionsError extends GenericError { + + const ERROR_ACTIONS_ACTION_DOES_NOT_EXIST = 110; + const ERROR_ACTIONS_DISABLED = 111; + const ERROR_ACTIONS_WRONG_EXITCODE = 112; + const ERROR_ACTIONS_NOT_CONFIGURED = 113; + + + const MSG_ERROR_ACTIONS_ACTION_DOES_NOT_EXIST = 'Action does not exist.'; + const MSG_ERROR_ACTIONS_DISABLED = 'Actions support is disabled.'; + const MSG_ERROR_ACTIONS_WRONG_EXITCODE = 'Action command returned wrong exitcode.'; + const MSG_ERROR_ACTIONS_NOT_CONFIGURED = 'Action is not configured.'; +} ?> diff --git a/gui/baculum/protected/Common/Class/Miscellaneous.php b/gui/baculum/protected/Common/Class/Miscellaneous.php index 9112bf001..e3654396a 100644 --- a/gui/baculum/protected/Common/Class/Miscellaneous.php +++ b/gui/baculum/protected/Common/Class/Miscellaneous.php @@ -87,10 +87,26 @@ class Miscellaneous extends TModule { private $runningJobStates = array('C', 'R'); private $components = array( - 'dir' => array('full_name' => 'Director', 'main_resource' => 'Director'), - 'sd' => array('full_name' => 'Storage Daemon', 'main_resource' => 'Storage'), - 'fd' => array('full_name' => 'File Daemon', 'main_resource' => 'FileDaemon'), - 'bcons' => array('full_name' => 'Console', 'main_resource' => 'Director') + 'dir' => array( + 'full_name' => 'Director', + 'url_name' => 'director', + 'main_resource' => 'Director' + ), + 'sd' => array( + 'full_name' => 'Storage Daemon', + 'url_name' => 'storage', + 'main_resource' => 'Storage' + ), + 'fd' => array( + 'full_name' => 'File Daemon', + 'url_name' => 'client', + 'main_resource' => 'FileDaemon' + ), + 'bcons' => array( + 'full_name' => 'Console', + 'url_name' => 'console', + 'main_resource' => 'Director' + ) ); private $replace_opts = array( @@ -143,6 +159,14 @@ class Miscellaneous extends TModule { return $name; } + public function getComponentUrlName($type) { + $name = ''; + if (key_exists($type, $this->components)) { + $name = $this->components[$type]['url_name']; + } + return $name; + } + public function getJobStatesByType($type) { $statesByType = array(); $states = array(); diff --git a/gui/baculum/themes/Baculum-v1/css/style.css b/gui/baculum/themes/Baculum-v1/css/style.css index bf76b40bb..f32cce2c0 100644 --- a/gui/baculum/themes/Baculum-v1/css/style.css +++ b/gui/baculum/themes/Baculum-v1/css/style.css @@ -311,18 +311,41 @@ h4 { width: 590px; float: left; } - +.actions_lines { + width: 743px; +} .config_lines div.field { width: 280px !important; } -#config_fields { +.actions_lines div.field { + width: 332px !important; +} + +#config_fields, #actions_fields { width: 732px; margin: 0 auto; padding-top: 7px; } +#actions_fields { + width: 810px; +} + +#actions_fields .button { + display: inline-block; + width: 50px; +} + +#actions_fields .button input[type="submit"] { + min-width: 60px; +} + +#actions_fields .action_test_loader, #actions_fields .action_success, #actions_fields .action_error { + margin-left: 11px; +} + #config_fields div.button { padding-left: 247px; } @@ -331,7 +354,11 @@ fieldset.config_field { width: 667px; } -fieldset.config_field .line { +fieldset.actions_field { + width: 745px; +} + +fieldset.config_field .line, fieldset.actions_field .line { height: auto; min-height: 35px !important; padding-top: 2px;