]> git.ipfire.org Git - thirdparty/bacula.git/commitdiff
baculum: Add query command support, object endpoint and m365 user list endpoint
authorMarcin Haba <marcin.haba@bacula.pl>
Wed, 10 Aug 2022 11:28:51 +0000 (13:28 +0200)
committerMarcin Haba <marcin.haba@bacula.pl>
Thu, 17 Nov 2022 09:05:10 +0000 (10:05 +0100)
15 files changed:
gui/baculum/protected/API/Modules/Bconsole.php
gui/baculum/protected/API/Modules/ConsoleOutputQueryPage.php [new file with mode: 0644]
gui/baculum/protected/API/Modules/ObjectManager.php [new file with mode: 0644]
gui/baculum/protected/API/Modules/ObjectRecord.php [new file with mode: 0644]
gui/baculum/protected/API/Modules/PluginConfig.php [new file with mode: 0644]
gui/baculum/protected/API/Modules/PluginFDConfig.php [new file with mode: 0644]
gui/baculum/protected/API/Pages/API/Objects.php [new file with mode: 0644]
gui/baculum/protected/API/Pages/API/PluginM365ListLoggedUsers.php [new file with mode: 0644]
gui/baculum/protected/API/Pages/API/config.xml
gui/baculum/protected/API/Pages/API/endpoints.xml
gui/baculum/protected/API/openapi_baculum.json
gui/baculum/protected/Common/Modules/Errors/ObjectError.php [new file with mode: 0644]
gui/baculum/protected/Common/Modules/Errors/PluginError.php [new file with mode: 0644]
gui/baculum/protected/Common/Modules/Errors/PluginM365Error.php [new file with mode: 0644]
gui/baculum/protected/Common/Modules/Miscellaneous.php

index ca15b71b29155c6ff0de1d5e79b537cc89861014..872a0454462442b320d3a518c5827d3e07f4eba4 100644 (file)
@@ -46,7 +46,7 @@ class Bconsole extends APIModule {
        const PTYPE_CONFIRM_YES_CMD = 3;
        const PTYPE_CONFIRM_YES_BG_CMD = 4;
 
-       const BCONSOLE_COMMAND_PATTERN = "%s%s -c \"%s\" %s 2>&1 <<END_OF_DATA\ngui on\n%s\nquit\nEND_OF_DATA";
+       const BCONSOLE_COMMAND_PATTERN = "%s%s -c \"%s\" %s 2>&1 <<END_OF_DATA\ngui on\n%s\n\nquit\nEND_OF_DATA";
 
        const BCONSOLE_BG_COMMAND_PATTERN = "echo 'gui on\n%s\nquit\n' | nohup %s%s -c \"%s\" %s >%s 2>&1 &";
 
@@ -96,7 +96,8 @@ class Bconsole extends APIModule {
                '.api',
                '.status',
                '.ls',
-               'setbandwidth'
+               'setbandwidth',
+               '.query'
        );
 
        private $config;
diff --git a/gui/baculum/protected/API/Modules/ConsoleOutputQueryPage.php b/gui/baculum/protected/API/Modules/ConsoleOutputQueryPage.php
new file mode 100644 (file)
index 0000000..23fa33e
--- /dev/null
@@ -0,0 +1,50 @@
+<?php
+/*
+ * Bacula(R) - The Network Backup Solution
+ * Baculum   - Bacula web interface
+ *
+ * Copyright (C) 2013-2022 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.
+ */
+
+namespace Baculum\API\Modules;
+
+/**
+ * Get console output for query type commands.
+ *
+ * @author Marcin Haba <marcin.haba@bacula.pl>
+ * @category API
+ * @package Baculum API
+ */
+abstract class ConsoleOutputQueryPage extends ConsoleOutputPage {
+
+       /**
+        * Parse '.query' type command output in key=value form.
+        *
+        * @param array $output dot query command output
+        * @return array parsed output
+        */
+       protected function parseOutputKeyValue(array $output) {
+               $ret = [];
+               for ($i = 0; $i < count($output); $i++) {
+                       if (preg_match('/(?P<key>\w+)=(?P<value>.+?)$/i', $output[$i], $matches) === 1) {
+                               $ret[$matches['key']] = $matches['value'];
+                       }
+               }
+               return $ret;
+       }
+}
+?>
diff --git a/gui/baculum/protected/API/Modules/ObjectManager.php b/gui/baculum/protected/API/Modules/ObjectManager.php
new file mode 100644 (file)
index 0000000..26154e4
--- /dev/null
@@ -0,0 +1,56 @@
+<?php
+/*
+ * Bacula(R) - The Network Backup Solution
+ * Baculum   - Bacula web interface
+ *
+ * Copyright (C) 2013-2022 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.
+ */
+
+namespace Baculum\API\Modules;
+
+/**
+ * Object manager module.
+ *
+ * @author Marcin Haba <marcin.haba@bacula.pl>
+ * @category Module
+ * @package Baculum API
+ */
+class ObjectManager extends APIModule {
+
+       public function getObjects($criteria = array(), $limit_val = null) {
+               $sort_col = 'ObjectId';
+               $db_params = $this->getModule('api_config')->getConfig('db');
+               if ($db_params['type'] === Database::PGSQL_TYPE) {
+                   $sort_col = strtolower($sort_col);
+               }
+               $order = ' ORDER BY ' . $sort_col . ' DESC';
+               $limit = '';
+               if(is_int($limit_val) && $limit_val > 0) {
+                       $limit = ' LIMIT ' . $limit_val;
+               }
+
+               $where = Database::getWhere($criteria);
+
+               $sql = 'SELECT Object.*, 
+Job.Name as jobname 
+FROM Object 
+LEFT JOIN Job USING (JobId) '
+. $where['where'] . $order . $limit;
+
+               return ObjectRecord::finder()->findAllBySql($sql, $where['params']);
+       }
+}
diff --git a/gui/baculum/protected/API/Modules/ObjectRecord.php b/gui/baculum/protected/API/Modules/ObjectRecord.php
new file mode 100644 (file)
index 0000000..ad45bf4
--- /dev/null
@@ -0,0 +1,57 @@
+<?php
+/*
+ * Bacula(R) - The Network Backup Solution
+ * Baculum   - Bacula web interface
+ *
+ * Copyright (C) 2013-2022 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.
+ */
+
+namespace Baculum\API\Modules;
+
+/**
+ * Object record module.
+ *
+ * @author Marcin Haba <marcin.haba@bacula.pl>
+ * @category Database
+ * @package Baculum API
+ */
+class ObjectRecord extends APIDbModule {
+
+       const TABLE = 'Object';
+
+       public $objectid;
+       public $jobid;
+       public $path;
+       public $filename;
+       public $pluginname;
+       public $objecttype;
+       public $objectname;
+       public $objectsource;
+       public $objectuuid;
+       public $objectsize;
+       public $objectcategory;
+       public $objectstatus;
+       public $objectcount;
+
+       // external properties
+       public $jobname;
+
+       public static function finder($className = __CLASS__) {
+               return parent::finder($className);
+       }
+}
+?>
diff --git a/gui/baculum/protected/API/Modules/PluginConfig.php b/gui/baculum/protected/API/Modules/PluginConfig.php
new file mode 100644 (file)
index 0000000..5ba969c
--- /dev/null
@@ -0,0 +1,47 @@
+<?php
+/*
+ * Bacula(R) - The Network Backup Solution
+ * Baculum   - Bacula web interface
+ *
+ * Copyright (C) 2013-2022 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.
+ */
+
+namespace Baculum\API\Modules;
+
+use Baculum\Common\Modules\ConfigFileModule;
+
+/**
+ * Generic plugin config module.
+ *
+ * @author Marcin Haba <marcin.haba@bacula.pl>
+ * @category Config
+ * @package Baculum API
+ */
+class PluginConfig extends ConfigFileModule {
+
+       /**
+        * Plugin config directory path.
+        */
+       const CONFIG_DIR_PATH = 'Baculum.API.Config.plugins';
+
+       /**
+        * Get plugin base directory for plugins configuration.
+        */
+       protected function getConfigDirPath() {
+               return self::CONFIG_DIR_PATH;
+       }
+}
diff --git a/gui/baculum/protected/API/Modules/PluginFDConfig.php b/gui/baculum/protected/API/Modules/PluginFDConfig.php
new file mode 100644 (file)
index 0000000..76e77cd
--- /dev/null
@@ -0,0 +1,72 @@
+<?php
+/*
+ * Bacula(R) - The Network Backup Solution
+ * Baculum   - Bacula web interface
+ *
+ * Copyright (C) 2013-2022 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.
+ */
+
+namespace Baculum\API\Modules;
+
+use Prado\Prado;
+
+/**
+ * File Daemon (Client) plugin config module.
+ * Module is responsible for read/write the config data.
+ *
+ * @author Marcin Haba <marcin.haba@bacula.pl>
+ * @category Config
+ * @package Baculum API
+ */
+class PluginFDConfig extends PluginConfig {
+
+       /**
+        * Plugin config file format.
+        */
+       const CONFIG_FILE_FORMAT = 'ini';
+
+       /**
+        * Plugin config file extension.
+        */
+       const CONFIG_FILE_EXT = '.conf';
+
+       private $config;
+
+       /**
+        * Get plugin client configuration.
+        *
+        * @param string $plugin plugin name (ex. 'm365' or 'mysql')
+        * @param string $client client name
+        * @param string $section if given, returned is this section from configuration
+        * @return array plugin client config
+        */
+       public function getConfig($plugin, $client, $section = null) {
+               $config = [];
+               if (is_null($this->config)) {
+                       $fn = sprintf('%s_%s', $client, $plugin);
+                       $cfg_dir_path = $this->getConfigDirPath();
+                       $path = Prado::getPathOfNamespace($cfg_dir_path) . DIRECTORY_SEPARATOR . $fn . self::CONFIG_FILE_EXT;
+                       $this->config = $this->readConfig($path, self::CONFIG_FILE_FORMAT);
+               }
+               if (!is_null($section)) {
+                       $config = key_exists($section, $this->config) ? $this->config[$section] : [];
+               } else {
+                       $config = $this->config;
+               }
+               return $config;
+       }
+}
diff --git a/gui/baculum/protected/API/Pages/API/Objects.php b/gui/baculum/protected/API/Pages/API/Objects.php
new file mode 100644 (file)
index 0000000..b8ecc8f
--- /dev/null
@@ -0,0 +1,78 @@
+<?php
+/*
+ * Bacula(R) - The Network Backup Solution
+ * Baculum   - Bacula web interface
+ *
+ * Copyright (C) 2013-2022 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.
+ */
+
+use Baculum\Common\Modules\Errors\ObjectError;
+
+/**
+ * Objects endpoint.
+ *
+ * @author Marcin Haba <marcin.haba@bacula.pl>
+ * @category API
+ * @package Baculum API
+ */
+class Objects extends BaculumAPIServer {
+
+       public function get() {
+               $misc = $this->getModule('misc');
+               $limit = $this->Request->contains('limit') ? intval($this->Request['limit']) : 0;
+               $objecttype = $this->Request->contains('objecttype') && $misc->isValidName($this->Request['objecttype']) ? $this->Request['objecttype'] : null;
+               $objectname = $this->Request->contains('objectname') && $misc->isValidName($this->Request['objectname']) ? $this->Request['objectname'] : null;
+               $objectcategory = $this->Request->contains('objectcategory') && $misc->isValidName($this->Request['objectcategory']) ? $this->Request['objectcategory'] : null;
+               $objectsource = $this->Request->contains('objectsource') && $misc->isValidName($this->Request['objectsource']) ? $this->Request['objectsource'] : null;
+               $objectuuid = $this->Request->contains('objectuuid') && $misc->isValidName($this->Request['objectuuid']) ? $this->Request['objectuuid'] : null;
+               $objectstatus = $this->Request->contains('objectstatus') && $misc->isValidState($this->Request['objectstatus']) ? $this->Request['objectstatus'] : null;
+               $jobname = $this->Request->contains('jobname') && $misc->isValidName($this->Request['jobname']) ? $this->Request['jobname'] : null;
+
+               $params = [];
+               if (!empty($objecttype)) {
+                       $params['Object.ObjectType']['operator'] = '';
+                       $params['Object.ObjectType']['vals'] = $objecttype;
+               }
+               if (!empty($objectname)) {
+                       $params['Object.ObjectName']['operator'] = '';
+                       $params['Object.ObjectName']['vals'] = $objectname;
+               }
+               if (!empty($objectcategory)) {
+                       $params['Object.ObjectCategory']['operator'] = '';
+                       $params['Object.ObjectCategory']['vals'] = $objectcategory;
+               }
+               if (!empty($objectsource)) {
+                       $params['Object.ObjectSource']['operator'] = '';
+                       $params['Object.ObjectSource']['vals'] = $objectsource;
+               }
+               if (!empty($objectuuid)) {
+                       $params['Object.ObjectUUID']['operator'] = '';
+                       $params['Object.ObjectUUID']['vals'] = $objectuuid;
+               }
+               if (!empty($objectstatus)) {
+                       $params['Object.ObjectStatus']['operator'] = '';
+                       $params['Object.ObjectStatus']['vals'] = $objectstatus;
+               }
+               if (!empty($jobname)) {
+                       $params['Job.Name']['operator'] = '';
+                       $params['Job.Name']['vals'] = $jobname;
+               }
+               $objects = $this->getModule('object')->getObjects($params, $limit);
+               $this->output = $objects;
+               $this->error = ObjectError::ERROR_NO_ERRORS;
+       }
+}
diff --git a/gui/baculum/protected/API/Pages/API/PluginM365ListLoggedUsers.php b/gui/baculum/protected/API/Pages/API/PluginM365ListLoggedUsers.php
new file mode 100644 (file)
index 0000000..a2effb8
--- /dev/null
@@ -0,0 +1,194 @@
+<?php
+/*
+ * Bacula(R) - The Network Backup Solution
+ * Baculum   - Bacula web interface
+ *
+ * Copyright (C) 2013-2022 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.
+ */
+
+use Baculum\API\Modules\ConsoleOutputPage;
+use Baculum\API\Modules\ConsoleOutputQueryPage;
+use Baculum\Common\Modules\Logging;
+use Baculum\Common\Modules\Errors\{BconsoleError,ClientError,PluginError,PluginM365Error};
+
+/**
+ * List logged in M365 plugin users.
+ *
+ * @author Marcin Haba <marcin.haba@bacula.pl>
+ * @category API
+ * @package Baculum API
+ */
+class PluginM365ListLoggedUsers extends ConsoleOutputQueryPage {
+
+       public function get() {
+               $misc = $this->getModule('misc');
+               $client = null;
+               $clientid = $this->Request->contains('id') ? (int)$this->Request['id'] : 0;
+               $result = $this->getModule('bconsole')->bconsoleCommand(
+                       $this->director,
+                       ['.client'],
+                       null,
+                       true
+               );
+               if ($result->exitcode === 0) {
+                       $client_val = $this->getModule('client')->getClientById($clientid);
+                       if (is_object($client_val) && in_array($client_val->name, $result->output)) {
+                               $client = $client_val->name;
+                       } else {
+                               $this->output = ClientError::MSG_ERROR_CLIENT_DOES_NOT_EXISTS;
+                               $this->error = ClientError::ERROR_CLIENT_DOES_NOT_EXISTS;
+                               return;
+                       }
+               } else {
+                       $this->output = PluginError::MSG_ERROR_WRONG_EXITCODE;
+                       $this->error = PluginError::ERROR_WRONG_EXITCODE;
+                       return;
+               }
+
+               $out_format = ConsoleOutputPage::OUTPUT_FORMAT_RAW;
+               if ($this->Request->contains('output') && $this->isOutputFormatValid($this->Request['output'])) {
+                       $out_format = $this->Request['output'];
+               }
+
+               $tenantid = $this->Request->contains('tenantid') ? $this->Request['tenantid'] : null;
+               if (!empty($tenantid) && !$misc->isValidUUID($tenantid)) {
+                       $this->output = PluginM365Error::MSG_ERROR_TENANT_DOES_NOT_EXISTS;
+                       $this->error = PluginM365Error::ERROR_TENANT_DOES_NOT_EXISTS;
+                       return;
+               }
+               $cfg = [];
+               $fd_plugin_cfg = $this->getModule('fd_plugin_cfg')->getConfig('m365', $client, $tenantid);
+               if (!empty($tenantid) && count($fd_plugin_cfg) > 0) {
+                       $cfg[$tenantid] = $fd_plugin_cfg;
+               } else {
+                       $cfg = $fd_plugin_cfg;
+               }
+
+               $output = [];
+               $error = 0;
+               foreach ($cfg as $tid => $opts) {
+                       $config_file = key_exists('config_file', $opts) ? $opts['config_file']: '';
+                       $objectid = key_exists('objectid', $opts) ? $opts['objectid']: '';
+                       $plugin = 'm365: ';
+                       if (!empty($config_file)) {
+                               // Standalone app model
+                               $plugin .= sprintf(' config_file=\"%s\" ', $config_file);
+                       } elseif (!empty($objectid)) {
+                               // Common app model
+                               $plugin .= sprintf(' objectid=\"%s\" ', $objectid);
+                       }
+
+                       $out = new \StdClass;
+                       $out->output = [];
+                       $out->error = BconsoleError::ERROR_NO_ERRORS;
+                       $params = ['client' => $client, 'plugin' => $plugin];
+                       if ($out_format === ConsoleOutputPage::OUTPUT_FORMAT_RAW) {
+                               $out = $this->getRawOutput($params);
+                       } elseif($out_format === ConsoleOutputPage::OUTPUT_FORMAT_JSON) {
+                               $out = $this->getJSONOutput($params);
+                       }
+
+                       if ($out->exitcode !== 0) {
+                               $error = PluginM365Error::ERROR_EXECUTING_PLUGIN_QUERY_COMMAND;
+                               $output = PluginM365Error::MSG_ERROR_EXECUTING_PLUGIN_QUERY_COMMAND . $out->output;
+                               $this->getModule('logging')->log(
+                                       Logging::CATEGORY_EXECUTE,
+                                       $output . ", Error=$error"
+                               );
+                               continue;
+                       }
+                       $output[$tid] = $out->output;
+               }
+               $this->output = $output;
+               $this->error = $error;
+       }
+
+       /**
+        * Get M365 logged user list output from console in raw format.
+        *
+        * @param array $params command parameters
+        * @return StdClass object with output and exitcode
+        */
+       protected function getRawOutput($params = []) {
+               $ret = $this->getModule('bconsole')->bconsoleCommand(
+                       $this->director,
+                       [
+                               '.query',
+                               'plugin="' . $params['plugin'] . '"',
+                               'client="' . $params['client'] . '"',
+                               'parameter="logged-users"'
+                       ]
+               );
+               if ($ret->exitcode === 0) {
+                       $ret->output = iterator_to_array($this->getUserRows($ret->output));
+               } else {
+                       $ret->output = []; // don't provide errors to output, only in logs
+                       $this->getModule('logging')->log(
+                               Logging::CATEGORY_EXECUTE,
+                               'Wrong output from m365 RAW user list: ' . implode(PHP_EOL, $ret->output)
+                       );
+               }
+               return $ret;
+       }
+
+       /**
+        * Get show director output in JSON format.
+        *
+        * @param array $params command parameters
+        * @return StdClass object with output and exitcode
+        */
+       protected function getJSONOutput($params = []) {
+               $ret = $this->getModule('bconsole')->bconsoleCommand(
+                       $this->director,
+                       [
+                               '.query',
+                               'plugin="' . $params['plugin'] . '"',
+                               'client="' . $params['client'] . '"',
+                               'parameter="json|logged-users"'
+                       ]
+               );
+               if ($ret->exitcode === 0) {
+                       $users = iterator_to_array($this->getUserJSON($ret->output));
+                       if (count($users) === 1) {
+                               $ret->output = json_decode($users[0]);
+                       } else {
+                               $ret->output = []; // don't provide errors to output, only in logs
+                               $this->getModule('logging')->log(
+                                       Logging::CATEGORY_EXECUTE,
+                                       'Wrong output from m365 JSON user list: ' . implode(PHP_EOL, $users)
+                               );
+                       }
+               }
+               return $ret;
+       }
+
+       private function getUserRows(array $output) {
+               for ($i = 0; $i < count($output); $i++) {
+                       if (preg_match('/^user=/', $output[$i]) === 1) {
+                               yield $output[$i];
+                       }
+               }
+       }
+
+       private function getUserJSON(array $output) {
+               for ($i = 0; $i < count($output); $i++) {
+                       if (preg_match('/^=?\[/', $output[$i]) === 1) {
+                               yield ltrim($output[$i], '=');
+                       }
+               }
+       }
+}
index 683b2e0ce053db454947b1a8aa40e1cbca80c657..96abe56cdcb2fe931e51260201e7ad396585bd71 100644 (file)
@@ -28,6 +28,7 @@
                <module id="storage" class="Baculum\API\Modules\StorageManager" />
                <module id="version" class="Baculum\API\Modules\VersionManager" />
                <module id="volume" class="Baculum\API\Modules\VolumeManager" />
+               <module id="object" class="Baculum\API\Modules\ObjectManager" />
                <!-- tools modules -->
                <module id="bconsole" class="Baculum\API\Modules\Bconsole" />
                <module id="json_tools" class="Baculum\API\Modules\JSONTools" />
@@ -54,5 +55,7 @@
                <module id="list" class="Baculum\API\Modules\BList" />
                <!-- changer command modules -->
                <module id="changer_command" class="Baculum\API\Modules\ChangerCommand" />
+               <!-- plugin modules -->
+               <module id="fd_plugin_cfg" class="Baculum\API\Modules\PluginFDConfig" />
        </modules>
 </configuration>
index 4f507d65d7db89a466686c2679cdbaaae48ae18b..d60165b90949a4f70419953de4be2d8437a30610 100644 (file)
@@ -1,5 +1,5 @@
 <urls>
-       <!-- #### NEW API version 1 #### -->
+       <!-- #### NEW API version 2 #### -->
 
        <!-- OAuth2 - only to be compatible with old OAuth2 endpoints -->
        <!-- Remove it in the future -->
@@ -87,6 +87,8 @@
        <url ServiceParameter="BVFSCleanUp" pattern="api/v2/bvfs/cleanup/" />
        <!-- joblog endpoints -->
        <url ServiceParameter="JobLog" pattern="api/v2/joblog/{id}/" parameters.id="\d+" />
+       <!-- event endpoints -->
+       <url ServiceParameter="Objects" pattern="api/v2/objects/" />
        <!-- @TODO: Separate this endpoint outside 'joblog' -->
        <url ServiceParameter="Messages" pattern="api/v2/joblog/messages" />
        <!-- fileset endpoints -->
        <!-- Basic user endpoints -->
        <url ServiceParameter="BasicUsers" pattern="api/v2/basic/users/" />
        <url ServiceParameter="BasicUser" pattern="api/v2/basic/users/{id}/" parameters.id="[a-zA-Z0-9]+" />
+       <!-- Plugins -->
+       <!-- M365 Plugin -->
+       <url ServiceParameter="PluginM365ListLoggedUsers" pattern="api/v2/plugins/m365/{id}/users/" parameters.id="\d+" />
 
-       <!-- API v1 -->
+       <!-- OLD API v1 -->
        <!-- general endpoint -->
        <url ServiceParameter="Welcome" pattern="api/v1/welcome/" />
        <!-- bconsole endpoints -->
index 4df9b3e05629fe26ba076a3d0972bc9f5c39332e..ff29591d9cd0f623ba42f02f5f32d3d343436fbf 100644 (file)
                        },
                        "AutochangerSlotVolume": {
                                "$ref": "#/definitions/AutochangerSlotVolume"
+                       },
+                       "Objects": {
+                               "type": "array",
+                               "items": {
+                                       "$ref": "#/definitions/Object"
+                               }
+                       },
+                       "Object": {
+                               "$ref": "#/definitions/Object"
                        }
                },
                "parameters": {
                                        "type": "boolean",
                                        "default": 0
                                }
+                       },
+                       "TenantId": {
+                               "name": "tenantid",
+                               "in": "query",
+                               "description": "Tenant identifier",
+                               "required": false,
+                               "schema": {
+                                       "type": "string"
+                               }
                        }
                }
        },
                                        }
                                ]
                        }
+               },
+               "/api/v2/objects": {
+                       "get": {
+                               "tags": ["objects"],
+                               "summary": "Object list",
+                               "description": "Get object list.",
+                               "responses": {
+                                       "200": {
+                                               "description": "List of objects",
+                                               "content": {
+                                                       "application/json": {
+                                                               "schema": {
+                                                                       "type": "object",
+                                                                       "properties": {
+                                                                               "output": {
+                                                                                       "$ref": "#/components/schemas/Objects"
+                                                                               },
+                                                                               "error": {
+                                                                                       "type": "integer",
+                                                                                       "description": "Error code",
+                                                                                       "enum": [0, 1, 2, 3, 4, 5, 6, 7, 11, 1000]
+                                                                               }
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               },
+                               "parameters": [
+                                       {
+                                               "$ref": "#/components/parameters/Limit"
+                                       },
+                                       {
+                                               "name": "objecttype",
+                                               "in": "query",
+                                               "required": false,
+                                               "description": "Object type, ex. 'm365' or 'PostgreSQL'",
+                                               "schema": {
+                                                       "type": "string"
+                                               }
+                                       },
+                                       {
+                                               "name": "objectname",
+                                               "in": "query",
+                                               "required": false,
+                                               "description": "Object name'",
+                                               "schema": {
+                                                       "type": "string"
+                                               }
+                                       },
+                                       {
+                                               "name": "objectcategory",
+                                               "in": "query",
+                                               "required": false,
+                                               "description": "Object category, ex: 'mailbox'",
+                                               "schema": {
+                                                       "type": "string"
+                                               }
+                                       },
+                                       {
+                                               "name": "objectsource",
+                                               "in": "query",
+                                               "required": false,
+                                               "description": "Object data source",
+                                               "schema": {
+                                                       "type": "string"
+                                               }
+                                       },
+                                       {
+                                               "name": "objectuuid",
+                                               "in": "query",
+                                               "required": false,
+                                               "description": "Object UUID",
+                                               "schema": {
+                                                       "type": "string"
+                                               }
+                                       },
+                                       {
+                                               "name": "objectstatus",
+                                               "in": "query",
+                                               "required": false,
+                                               "description": "Object status ex: 'T', 'e' ...",
+                                               "schema": {
+                                                       "type": "string"
+                                               }
+                                       },
+                                       {
+                                               "name": "jobname",
+                                               "in": "query",
+                                               "required": false,
+                                               "description": "Job name",
+                                               "schema": {
+                                                       "type": "string"
+                                               }
+                                       }
+                               ]
+                       }
+               },
+               "/api/v2/plugins/m365/{clientid}/users": {
+                       "get": {
+                               "tags": ["plugins"],
+                               "summary": "Microsoft 365 plugin logged in user list",
+                               "description": "Get Microsoft 365 logged in user list.",
+                               "responses": {
+                                       "200": {
+                                               "description": "List of Microsoft 365 users",
+                                               "content": {
+                                                       "application/json": {
+                                                               "schema": {
+                                                                       "type": "object",
+                                                                       "properties": {
+                                                                               "output": {
+                                                                                       "type": "object",
+                                                                                       "properties": {
+                                                                                               "tenantid": {
+                                                                                                       "type": "array",
+                                                                                                       "description": "Microsoft 365 users"
+                                                                                               }
+                                                                                       }
+                                                                               },
+                                                                               "error": {
+                                                                                       "type": "integer",
+                                                                                       "description": "Error code",
+                                                                                       "enum": [0, 1, 4, 5, 6, 7, 11, 1000]
+                                                                               }
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               },
+                               "parameters": [
+                                       {
+                                               "$ref": "#/components/parameters/ClientId"
+                                       },
+                                       {
+                                               "$ref": "#/components/parameters/TenantId"
+                                       },
+                                       {
+                                               "$ref": "#/components/parameters/Output"
+                                       }
+                               ]
+                       }
                }
        },
        "definitions": {
                                        "type": "integer"
                                }
                        }
+               },
+               "Object": {
+                       "type": "object",
+                       "properties": {
+                               "objectid": {
+                                       "description": "Object identifier",
+                                       "type": "integer"
+                               },
+                               "jobid": {
+                                       "description": "Job identifier",
+                                       "type": "integer"
+                               },
+                               "path": {
+                                       "description": "Object path, ex: /@m365/n45/users/john@finger/email/",
+                                       "type": "string"
+                               },
+                               "filename": {
+                                       "description": "Object file name",
+                                       "type": "string"
+                               },
+                               "pluginname": {
+                                       "description": "Plugin definition in form 'plugin_name: param1=value1 param2=value2 ...'",
+                                       "type": "string"
+                               },
+                               "objecttype": {
+                                       "description": "Object type, ex. 'm365' or 'PostgreSQL'",
+                                       "type": "string"
+                               },
+                               "objectname": {
+                                       "description": "Object name",
+                                       "type": "string"
+                               },
+                               "objectsource": {
+                                       "description": "Object data source",
+                                       "type": "string"
+                               },
+                               "objectuuid": {
+                                       "description": "Object UUID",
+                                       "type": "string"
+                               },
+                               "objectsize": {
+                                       "description": "Object size",
+                                       "type": "integer"
+                               },
+                               "objectcategory": {
+                                       "description": "Object category, ex: 'mailbox'",
+                                       "type": "string"
+                               },
+                               "objectstatus": {
+                                       "description": "Object status ex: 'T', 'e' ...",
+                                       "type": "string"
+                               },
+                               "objectcount": {
+                                       "description": "Object count",
+                                       "type": "integer"
+                               }
+                       }
                }
        }
 }
diff --git a/gui/baculum/protected/Common/Modules/Errors/ObjectError.php b/gui/baculum/protected/Common/Modules/Errors/ObjectError.php
new file mode 100644 (file)
index 0000000..afba519
--- /dev/null
@@ -0,0 +1,36 @@
+<?php
+/*
+ * Bacula(R) - The Network Backup Solution
+ * Baculum   - Bacula web interface
+ *
+ * Copyright (C) 2013-2022 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.
+ */
+
+namespace Baculum\Common\Modules\Errors;
+
+/**
+ * Object error class.
+ *
+ * @author Marcin Haba <marcin.haba@bacula.pl>
+ * @category Errors
+ * @package Baculum Common
+ */
+class ObjectError extends GenericError {
+       const ERROR_OBJECT_DOES_NOT_EXISTS = 500;
+
+       const MSG_ERROR_OBJECT_DOES_NOT_EXISTS = 'Object does not exist.';
+}
diff --git a/gui/baculum/protected/Common/Modules/Errors/PluginError.php b/gui/baculum/protected/Common/Modules/Errors/PluginError.php
new file mode 100644 (file)
index 0000000..480bf6a
--- /dev/null
@@ -0,0 +1,36 @@
+<?php
+/*
+ * Bacula(R) - The Network Backup Solution
+ * Baculum   - Bacula web interface
+ *
+ * Copyright (C) 2013-2022 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.
+ */
+
+namespace Baculum\Common\Modules\Errors;
+
+/**
+ * Generic plugin error class.
+ *
+ * @author Marcin Haba <marcin.haba@bacula.pl>
+ * @category Errors
+ * @package Baculum Common
+ */
+class PluginError extends GenericError {
+       const ERROR_EXECUTING_PLUGIN_QUERY_COMMAND = 150;
+
+       const MSG_ERROR_EXECUTING_PLUGIN_QUERY_COMMAND = 'Error executing plugin query command.';
+}
diff --git a/gui/baculum/protected/Common/Modules/Errors/PluginM365Error.php b/gui/baculum/protected/Common/Modules/Errors/PluginM365Error.php
new file mode 100644 (file)
index 0000000..9b3f1ed
--- /dev/null
@@ -0,0 +1,36 @@
+<?php
+/*
+ * Bacula(R) - The Network Backup Solution
+ * Baculum   - Bacula web interface
+ *
+ * Copyright (C) 2013-2022 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.
+ */
+
+namespace Baculum\Common\Modules\Errors;
+
+/**
+ * Microsoft 365 plugin error class.
+ *
+ * @author Marcin Haba <marcin.haba@bacula.pl>
+ * @category Errors
+ * @package Baculum Common
+ */
+class PluginM365Error extends PluginError {
+       const ERROR_TENANT_DOES_NOT_EXISTS = 160;
+
+       const MSG_ERROR_TENANT_DOES_NOT_EXISTS = 'Tenant does not exist.';
+}
index 6521a08bbdb1034d0d773811280b165cd230b007..9bebc11c1bb41959623c5aabccd4158e68bb0bbe 100644 (file)
@@ -286,6 +286,10 @@ class Miscellaneous extends TModule {
                return (preg_match('/^(raw|json)$/', $type) === 1);
        }
 
+       public function isValidUUID($uuid) {
+               return (preg_match('/^[\w]{8}(-[\w]{4}){3}-[\w]{12}$/', $uuid) === 1);
+       }
+
        public function escapeCharsToConsole($path) {
                return preg_replace('/([$])/', '\\\${1}', $path);
        }