diff --git a/CHANGELOG.md b/CHANGELOG.md index ea0f6ed14b9..9779e79ec26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ and since Bareos version 20 this project adheres to [Semantic Versioning](https: - webui: update localization [PR #1414] - webui: improve localization process [PR #1429] - webui: add machine-readable copyright file [PR #1419] +- webui: add config resource graph to analytics (experimental) [PR #1412] ### Removed - remove no longer used pkglists [PR #1335] @@ -109,6 +110,7 @@ and since Bareos version 20 this project adheres to [Semantic Versioning](https: [PR #1403]: https://github.com/bareos/bareos/pull/1403 [PR #1407]: https://github.com/bareos/bareos/pull/1407 [PR #1410]: https://github.com/bareos/bareos/pull/1410 +[PR #1412]: https://github.com/bareos/bareos/pull/1412 [PR #1414]: https://github.com/bareos/bareos/pull/1414 [PR #1415]: https://github.com/bareos/bareos/pull/1415 [PR #1419]: https://github.com/bareos/bareos/pull/1419 diff --git a/docs/manuals/source/IntroductionAndTutorial/BareosWebui.rst b/docs/manuals/source/IntroductionAndTutorial/BareosWebui.rst index 340ae392a4e..abdae728860 100644 --- a/docs/manuals/source/IntroductionAndTutorial/BareosWebui.rst +++ b/docs/manuals/source/IntroductionAndTutorial/BareosWebui.rst @@ -527,6 +527,13 @@ Some parameters of the |webui| can be configured in :file:`/etc/bareos-webui/con ; Default: ;name=sunflower + ;------------------------------------------------------------------------------ + ; EXPERIMENTAL FEATURES + ;------------------------------------------------------------------------------ + ;[experimental] + ; Configuration resource graph + ; Default: + ;configuration_resource_graph=false .. _section-updating-bvfs-cache-frequently: diff --git a/webui/config/autoload/global.php.in b/webui/config/autoload/global.php.in index 5e93e704a45..f114fe07d88 100644 --- a/webui/config/autoload/global.php.in +++ b/webui/config/autoload/global.php.in @@ -76,10 +76,10 @@ function read_configuration_ini($configuration_ini) 'save_previous_state' => false, ), /* - 'autochanger' => array( - 'labelpooltype' => , - ), - */ + 'autochanger' => array( + 'labelpooltype' => , + ), + */ 'dashboard' => array( 'autorefresh_interval' => 60000, ), @@ -88,6 +88,9 @@ function read_configuration_ini($configuration_ini) ), 'theme' => array( 'name' => "sunflower" + ), + 'experimental' => array( + 'configuration_resource_graph' => false ) ); @@ -120,6 +123,9 @@ function read_configuration_ini($configuration_ini) if (isset($configuration['theme']['name'])) { $result['theme']['name'] = $configuration['theme']['name']; } + if (isset($configuration['experimental']['configuration_resource_graph'])) { + $result['experimental']['configuration_resource_graph'] = $configuration['experimental']['configuration_resource_graph']; + } } return $result; diff --git a/webui/install/configuration.ini.in b/webui/install/configuration.ini.in index 25ed6820749..85d319bce3f 100644 --- a/webui/install/configuration.ini.in +++ b/webui/install/configuration.ini.in @@ -8,7 +8,7 @@ ; SESSION SETTINGS ;------------------------------------------------------------------------------ ; -;[session] +[session] ; Session timeout in seconds ; Default: ;timeout=3600 @@ -16,7 +16,7 @@ ;------------------------------------------------------------------------------ ; DASHBOARD SETTINGS ;------------------------------------------------------------------------------ -;[dashboard] +[dashboard] ; Autorefresh Interval in milliseconds ; Default: ;autorefresh_interval=60000 @@ -24,7 +24,7 @@ ;------------------------------------------------------------------------------ ; TABLE SETTINGS ;------------------------------------------------------------------------------ -;[tables] +[tables] ; Possible values for pagination ; Default: ;pagination_values=10,25,50,100 @@ -41,12 +41,12 @@ ;------------------------------------------------------------------------------ ; VARIOUS SETTINGS ;------------------------------------------------------------------------------ -;[autochanger] +[autochanger] ; Name of the pool used to label and assign new media, e.g. Scratch. ; Default: ;labelpooltype= -;[restore] +[restore] ; Restore filetree refresh timeout in milliseconds ; Default: ;filetree_refresh_timeout=120000 @@ -54,8 +54,15 @@ ;------------------------------------------------------------------------------ ; THEME SETTINGS ;------------------------------------------------------------------------------ -;[theme] +[theme] ; Possible values: default, sunflower ; Default: ;name=sunflower +;------------------------------------------------------------------------------ +; EXPERIMENTAL FEATURES +;------------------------------------------------------------------------------ +[experimental] +; Configuration resource graph +; Default: +;configuration_resource_graph=false diff --git a/webui/module/Analytics/src/Analytics/Controller/AnalyticsController.php b/webui/module/Analytics/src/Analytics/Controller/AnalyticsController.php index b5f2c986b53..c60f204f324 100644 --- a/webui/module/Analytics/src/Analytics/Controller/AnalyticsController.php +++ b/webui/module/Analytics/src/Analytics/Controller/AnalyticsController.php @@ -73,6 +73,43 @@ public function indexAction() return new ViewModel(); } + public function configurationAction() + { + $this->RequestURIPlugin()->setRequestURI(); + + if (!$this->SessionTimeoutPlugin()->isValid()) { + return $this->redirect()->toRoute( + 'auth', + array( + 'action' => 'login' + ), + array( + 'query' => array( + 'req' => $this->RequestURIPlugin()->getRequestURI(), + 'dird' => $_SESSION['bareos']['director'] + ) + ) + ); + } + + $module_config = $this->getServiceLocator()->get('ModuleManager')->getModule('Application')->getConfig(); + $invalid_commands = $this->CommandACLPlugin()->getInvalidCommands( + $module_config['console_commands']['Analytics']['mandatory'] + ); + + if (count($invalid_commands) > 0) { + $this->acl_alert = true; + return new ViewModel( + array( + 'acl_alert' => $this->acl_alert, + 'invalid_commands' => implode(",", $invalid_commands) + ) + ); + } + + return new ViewModel(); + } + public function getDataAction() { $this->RequestURIPlugin()->setRequestURI(); @@ -112,6 +149,14 @@ public function getDataAction() } catch (Exception $e) { echo $e->getMessage(); } + } elseif ($data == "config-resource-graph") { + try { + $this->bsock = $this->getServiceLocator()->get('director'); + $result = $this->getAnalyticsModel()->getConfigResourceGraph($this->bsock); + $this->bsock->disconnect(); + } catch (Exception $e) { + echo $e->getMessage(); + } } $response = $this->getResponse(); diff --git a/webui/module/Analytics/src/Analytics/Model/AnalyticsModel.php b/webui/module/Analytics/src/Analytics/Model/AnalyticsModel.php index 3b7dab9e864..bd288f8de71 100644 --- a/webui/module/Analytics/src/Analytics/Model/AnalyticsModel.php +++ b/webui/module/Analytics/src/Analytics/Model/AnalyticsModel.php @@ -52,4 +52,146 @@ public function getOverallJobTotals(&$bsock = null) throw new \Exception('Missing argument.'); } } + + public function getConfigResourceId($type, &$name) + { + # valid CSS id can only contain characters [a-zA-Z0-9-_] + return $type . "_" . md5($name); + } + + public function createConfigResourceNode($type, &$resource) + { + $node = new \stdClass(); + $node->type = $type; + $node->id = $this->getConfigResourceId($type, $resource["name"]); + $node->name = $resource["name"]; + $node->resource = $resource; + return $node; + } + + + public function getConfigResourceGraph(&$bsock = null) + { + if (!isset($bsock)) { + throw new \Exception('Missing argument.'); + } + + $cmd = 'show clients'; + $result = $bsock->send_command($cmd, 2); + $clients = \Zend\Json\Json::decode($result, \Zend\Json\Json::TYPE_ARRAY); + $clients_cache = $clients['result']['clients']; + + $cmd = 'show jobs'; + $result = $bsock->send_command($cmd, 2); + $jobs = \Zend\Json\Json::decode($result, \Zend\Json\Json::TYPE_ARRAY); + $jobs_cache = $jobs['result']['jobs']; + + $cmd = 'show jobdefs'; + $result = $bsock->send_command($cmd, 2); + $jobdefs = \Zend\Json\Json::decode($result, \Zend\Json\Json::TYPE_ARRAY); + $jobdefs_cache = $jobdefs['result']['jobdefs']; + + $cmd = 'show fileset'; + $result = $bsock->send_command($cmd, 2); + $filesets = \Zend\Json\Json::decode($result, \Zend\Json\Json::TYPE_ARRAY); + $filesets_cache = $filesets['result']['filesets']; + + $cmd = 'show schedules'; + $result = $bsock->send_command($cmd, 2); + $schedules = \Zend\Json\Json::decode($result, \Zend\Json\Json::TYPE_ARRAY); + $schedules_cache = $schedules['result']['schedules']; + + $config_graph = new \stdClass(); + $nodes = array(); + $links = array(); + + foreach ($clients_cache as $client_key => $client) { + $node = $this->createConfigResourceNode("client", $client); + array_push($nodes, $node); + foreach ($jobs_cache as $job_key => $job) { + if (isset($job['client'])) { + if ($client["name"] === $job["client"]) { + $link = new \stdClass(); + $link->source = $node->id; + $link->target = $this->getConfigResourceId("job", $job["name"]); + array_push($links, $link); + } + } + } + } + foreach ($jobs_cache as $job_key => $job) { + $node = $this->createConfigResourceNode("job", $job); + array_push($nodes, $node); + if (isset($job["jobdefs"])) { + foreach ($jobdefs_cache as $jobdefs_key => $jobdefs) { + if ($job["jobdefs"] === $jobdefs["name"]) { + $link = new \stdClass(); + $link->source = $node->id; + $link->target = $this->getConfigResourceId("jobdefs", $jobdefs["name"]); + array_push($links, $link); + } + } + } + if (isset($job["schedule"])) { + foreach ($schedules_cache as $schedule_key => $schedule) { + if ($job["schedule"] === $schedule["name"]) { + $link = new \stdClass(); + $link->source = $node->id; + $link->target = $this->getConfigResourceId("schedule", $schedule["name"]); + array_push($links, $link); + } + } + } + if (isset($job["fileset"])) { + foreach ($filesets_cache as $filesets_key => $fileset) { + if ($job["fileset"] === $fileset["name"]) { + $link = new \stdClass(); + $link->source = $node->id; + $link->target = $this->getConfigResourceId("fileset", $fileset["name"]); + array_push($links, $link); + } + } + } + } + + foreach ($filesets_cache as $fileset_key => $fileset) { + $node = $this->createConfigResourceNode("fileset", $fileset); + array_push($nodes, $node); + } + + foreach ($jobdefs_cache as $jobdefs_key => $jobdefs) { + $node = $this->createConfigResourceNode("jobdefs", $jobdefs); + array_push($nodes, $node); + if (isset($jobdefs["schedule"])) { + foreach ($schedules_cache as $schedule_key => $schedule) { + if ($jobdefs["schedule"] === $schedule["name"]) { + $link = new \stdClass(); + $link->source = $node->id; + $link->target = $this->getConfigResourceId("schedule", $schedule["name"]); + array_push($links, $link); + } + } + } + if (isset($jobdefs["fileset"])) { + foreach ($filesets_cache as $fileset_key => $fileset) { + if ($jobdefs["fileset"] === $fileset["name"]) { + $link = new \stdClass(); + $link->source = $node->id; + $link->target = $this->getConfigResourceId("fileset", $fileset["name"]); + array_push($links, $link); + } + } + } + } + + foreach ($schedules_cache as $schedule_key => $schedule) { + $node = $this->createConfigResourceNode("schedule", $schedule); + array_push($nodes, $node); + } + + $config_graph->nodes = $nodes; + $config_graph->links = $links; + + return $config_graph; + } } diff --git a/webui/module/Analytics/view/analytics/analytics/configuration.phtml b/webui/module/Analytics/view/analytics/analytics/configuration.phtml new file mode 100644 index 00000000000..764257e0f4d --- /dev/null +++ b/webui/module/Analytics/view/analytics/analytics/configuration.phtml @@ -0,0 +1,376 @@ +. + * + */ + +$title = _('Analytics'); +$this->headTitle($title); + +?> + +acl_alert) : echo $this->ACLAlert($this->invalid_commands); elseif(!$this->acl_alert) : ?> + + + +
+ +
+
+ +
+
+
+
+

translate("Configuration Resource"); ?>

+
+
+
+
+
+
+
+ +headScript()->prependFile($this->basePath() . '/js/d3/d3.min.js'); +?> + + + + + + diff --git a/webui/module/Analytics/view/analytics/analytics/index.phtml b/webui/module/Analytics/view/analytics/analytics/index.phtml index 10e784823a2..1b8c3395d8f 100644 --- a/webui/module/Analytics/view/analytics/analytics/index.phtml +++ b/webui/module/Analytics/view/analytics/analytics/index.phtml @@ -5,7 +5,7 @@ * bareos-webui - Bareos Web-Frontend * * @link https://github.com/bareos/bareos for the canonical source repository - * @copyright Copyright (c) 2013-2022 Bareos GmbH & Co. KG (http://www.bareos.org/) + * @copyright Copyright (c) 2013-2023 Bareos GmbH & Co. KG (http://www.bareos.org/) * @license GNU Affero General Public License (http://www.gnu.org/licenses/) * * This program is free software: you can redistribute it and/or modify @@ -31,7 +31,14 @@ $this->headTitle($title); acl_alert) : echo $this->ACLAlert($this->invalid_commands); elseif(!$this->acl_alert) : ?>
diff --git a/webui/module/Auth/src/Auth/Controller/AuthController.php b/webui/module/Auth/src/Auth/Controller/AuthController.php index 1e493c44300..a96d7c26919 100644 --- a/webui/module/Auth/src/Auth/Controller/AuthController.php +++ b/webui/module/Auth/src/Auth/Controller/AuthController.php @@ -125,6 +125,7 @@ public function loginAction() $session->offsetSet('dt_statesave', ($configuration['configuration']['tables']['save_previous_state']) ? 'true' : 'false'); $session->offsetSet('dashboard_autorefresh_interval', $configuration['configuration']['dashboard']['autorefresh_interval']); $session->offsetSet('filetree_refresh_timeout', $configuration['configuration']['restore']['filetree_refresh_timeout']); + $session->offsetSet('configuration_resource_graph', $configuration['configuration']['experimental']['configuration_resource_graph']); if (isset($configuration['configuration']['autochanger']['labelpooltype'])) { $session->offsetSet('ac_labelpooltype', $configuration['configuration']['autochanger']['labelpooltype']);