]> git.ipfire.org Git - thirdparty/bacula.git/commitdiff
baculum: Add API endpoints to label volume with and without barcodes
authorMarcin Haba <marcin.haba@bacula.pl>
Thu, 9 May 2019 14:40:06 +0000 (16:40 +0200)
committerMarcin Haba <marcin.haba@bacula.pl>
Sat, 14 Dec 2019 14:50:00 +0000 (15:50 +0100)
gui/baculum/protected/API/Class/Bconsole.php
gui/baculum/protected/API/Pages/API/ComponentStatus.php
gui/baculum/protected/API/Pages/API/ScheduleStatus.php
gui/baculum/protected/API/Pages/API/VolumeLabel.php [new file with mode: 0644]
gui/baculum/protected/API/Pages/API/VolumeLabelBarcodes.php [new file with mode: 0644]
gui/baculum/protected/API/endpoints.xml
gui/baculum/protected/Common/Class/Errors.php
gui/baculum/protected/Common/Class/Miscellaneous.php

index f1c801384abe4e85033225e68673fdc44c63e057..be1e04cf8dfac4f3c4522aff5b254f3cbc11edef 100644 (file)
@@ -28,8 +28,17 @@ class Bconsole extends APIModule {
 
        const SUDO = 'sudo';
 
+       /**
+        * Pattern types used to prepare command.
+        */
+       const PTYPE_REG_CMD = 0;
+       const PTYPE_API_CMD = 1;
+       const PTYPE_CONFIRM_YES_CMD = 2;
+
        const BCONSOLE_COMMAND_PATTERN = "%s%s -c %s %s 2>&1 <<END_OF_DATA\ngui on\n%s\nquit\nEND_OF_DATA";
 
+       const BCONSOLE_CONFIRM_YES_COMMAND_PATTERN = "%s%s -c %s %s 2>&1 <<END_OF_DATA\ngui on\n%s\nyes\nquit\nEND_OF_DATA";
+
        const BCONSOLE_API_COMMAND_PATTERN = "%s%s -c %s %s 2>&1 <<END_OF_DATA\ngui on\n.api 2 nosignal api_opts=o\n%s\nquit\nEND_OF_DATA";
 
        const BCONSOLE_DIRECTORS_PATTERN = "%s%s -c %s -l 2>&1";
@@ -149,7 +158,7 @@ class Bconsole extends APIModule {
                return (object)array('output' => $output, 'exitcode' => (integer)$exitcode);
        }
 
-       public function bconsoleCommand($director, array $command, $api = false) {
+       public function bconsoleCommand($director, array $command, $ptype = null) {
                if (count($this->config) > 0 && $this->config['enabled'] !== '1') {
                        throw new BConsoleException(
                                BconsoleError::MSG_ERROR_BCONSOLE_DISABLED,
@@ -158,7 +167,7 @@ class Bconsole extends APIModule {
                }
                $base_command = count($command) > 0 ? $command[0] : null;
                if($this->isCommandValid($base_command) === true) {
-                       $result = $this->execCommand($director, $command, $api);
+                       $result = $this->execCommand($director, $command, $ptype);
                } else {
                        throw new BConsoleException(
                                BconsoleError::MSG_ERROR_INVALID_COMMAND,
@@ -168,7 +177,7 @@ class Bconsole extends APIModule {
                return $result;
        }
 
-       private function execCommand($director, array $command, $api = false) {
+       private function execCommand($director, array $command, $ptype = null) {
                $cmd = '';
                $result = null;
                if(!is_null($director) && $this->isValidDirector($director) === false) {
@@ -180,7 +189,12 @@ class Bconsole extends APIModule {
                        $dir = is_null($director) ? '': '-D ' . $director;
                        $sudo = ($this->getUseSudo() === true) ? self::SUDO . ' ' : '';
                        $bconsole_command = implode(' ', $command);
-                       $pattern = ($api === true) ? self::BCONSOLE_API_COMMAND_PATTERN : self::BCONSOLE_COMMAND_PATTERN;
+                       $pattern = null;
+                       switch ($ptype) {
+                               case self::PTYPE_API_CMD: $pattern = self::BCONSOLE_API_COMMAND_PATTERN; break;
+                               case self::PTYPE_CONFIRM_YES_CMD: $pattern = self::BCONSOLE_CONFIRM_YES_COMMAND_PATTERN; break;
+                               default: $pattern = self::BCONSOLE_COMMAND_PATTERN;
+                       }
                        $cmd = sprintf(
                                $pattern,
                                $sudo,
index d813cb5e446ad64d8380b558d8aeea7c3f035e62..c809eaba7cefab4688d8c98b7faea55fd28bb82b 100644 (file)
@@ -3,7 +3,7 @@
  * Bacula(R) - The Network Backup Solution
  * Baculum   - Bacula web interface
  *
- * Copyright (C) 2013-2018 Kern Sibbald
+ * Copyright (C) 2013-2019 Kern Sibbald
  *
  * The main author of Baculum is Marcin Haba.
  * The original author of Bacula is Kern Sibbald, with contributions
@@ -20,6 +20,8 @@
  * Bacula(R) is a registered trademark of Kern Sibbald.
  */
 
+Prado::using('Application.API.Class.Bconsole');
+
 /**
  * Component status module.
  */
@@ -36,7 +38,7 @@ class ComponentStatus extends BaculumAPIServer {
                                $result = $this->getModule('bconsole')->bconsoleCommand(
                                        $this->director,
                                        array('status', 'director'),
-                                       true
+                                       Bconsole::PTYPE_API_CMD
                                );
                                if ($result->exitcode === 0) {
                                        $output = $this->getModule('status_dir')->getStatus($result->output);
@@ -62,7 +64,7 @@ class ComponentStatus extends BaculumAPIServer {
                                $result = $this->getModule('bconsole')->bconsoleCommand(
                                        $this->director,
                                        array('.status', $storage, $type),
-                                       true
+                                       Bconsole::PTYPE_API_CMD
                                );
                                if ($result->exitcode === 0) {
                                        $this->output = $this->getModule('status_sd')->getStatus($result->output);
index 4b8acf9525c58d53d4d5580b79f76ad6941c57c4..b5e2283cf281a3dadb61e1ef4ed8d0fb012f68b2 100644 (file)
@@ -20,6 +20,8 @@
  * Bacula(R) is a registered trademark of Kern Sibbald.
  */
 
+Prado::using('Application.API.Class.Bconsole');
+
 class ScheduleStatus extends BaculumAPIServer {
 
        public function get() {
@@ -44,7 +46,7 @@ class ScheduleStatus extends BaculumAPIServer {
                        $cmd[] = 'time="' . $this->Request['time'] . '"';
                }
 
-               $result = $this->getModule('bconsole')->bconsoleCommand($this->director, $cmd, true);
+               $result = $this->getModule('bconsole')->bconsoleCommand($this->director, $cmd, Bconsole::PTYPE_API_CMD);
                if ($result->exitcode === 0) {
                        array_shift($result->output);
                        $this->output = $this->formatSchedules($result->output);
diff --git a/gui/baculum/protected/API/Pages/API/VolumeLabel.php b/gui/baculum/protected/API/Pages/API/VolumeLabel.php
new file mode 100644 (file)
index 0000000..7c991ea
--- /dev/null
@@ -0,0 +1,136 @@
+<?php
+/*
+ * Bacula(R) - The Network Backup Solution
+ * Baculum   - Bacula web interface
+ *
+ * Copyright (C) 2013-2019 Kern Sibbald
+ *
+ * The main author of Baculum is Marcin Haba.
+ * The original author of Bacula is Kern Sibbald, with contributions
+ * from many others, a complete list can be found in the file AUTHORS.
+ *
+ * You may use this file and others of this release according to the
+ * license defined in the LICENSE file, which includes the Affero General
+ * Public License, v3.0 ("AGPLv3") and some additional permissions and
+ * terms pursuant to its AGPLv3 Section 7.
+ *
+ * This notice must be preserved when any source code is
+ * conveyed and/or propagated.
+ *
+ * Bacula(R) is a registered trademark of Kern Sibbald.
+ */
+
+Prado::using('Application.API.Class.Bconsole');
+
+class VolumeLabel extends BaculumAPIServer {
+
+       public function create($params) {
+               $volume = property_exists($params, 'volume') ? $params->volume : 0;
+               $slot = property_exists($params, 'slot') ? $params->slot : 0;
+               $drive = property_exists($params, 'drive') ? intval($params->drive) : 0;
+               $poolid = property_exists($params, 'poolid') ? intval($params->poolid) : 0;
+               $misc = $this->getModule('misc');
+
+               if (!$misc->isValidName($volume)) {
+                       $this->output = VolumeError::ERROR_INVALID_VOLUME;
+                       $this->error = VolumeError::MSG_ERROR_INVALID_VOLUME;
+                       return;
+               }
+
+               if (!$misc->isValidInteger($slot)) {
+                       $this->output = VolumeError::ERROR_INVALID_SLOT;
+                       $this->error = VolumeError::MSG_ERROR_INVALID_SLOT;
+                       return;
+               }
+
+               $storage = null;
+               if (property_exists($params, 'storageid')) {
+                       $storageid = intval($params->storageid);
+                       $result = $this->getModule('storage')->getStorageById($storageid);
+                       if (is_object($result)) {
+                               $storage = $result->name;
+                       }
+               } elseif (property_exists($params, 'storage') && $misc->isValidName($params->storage)) {
+                       $storage = $params->storage;
+               }
+
+               $pool = null;
+               if (property_exists($params, 'poolid')) {
+                       $poolid = intval($params->poolid);
+                       $result = $this->getModule('pool')->getPoolById($poolid);
+                       if (is_object($result)) {
+                               $pool = $result->name;
+                       }
+               } elseif (property_exists($params, 'pool') && $misc->isValidName($params->pool)) {
+                       $pool = $params->pool;
+               }
+
+               if (!is_null($storage)) {
+                       $result = $this->getModule('bconsole')->bconsoleCommand(
+                               $this->director,
+                               array('.storage')
+                       );
+                       if ($result->exitcode === 0) {
+                               array_shift($result->output);
+                               if (!in_array($storage, $result->output)) {
+                                       $this->output = StorageError::MSG_ERROR_STORAGE_DOES_NOT_EXISTS;
+                                       $this->error = StorageError::ERROR_STORAGE_DOES_NOT_EXISTS;
+                                       return;
+                               }
+                       } else {
+                               $this->output = $result->output;
+                               $this->error = $result->exitcode;
+                               return;
+                       }
+               } else {
+                       $this->output = StorageError::MSG_ERROR_STORAGE_DOES_NOT_EXISTS;
+                       $this->error = StorageError::ERROR_STORAGE_DOES_NOT_EXISTS;
+                       return;
+               }
+
+               if (!is_null($pool)) {
+                       $result = $this->getModule('bconsole')->bconsoleCommand(
+                               $this->director,
+                               array('.pool')
+                       );
+                       if ($result->exitcode === 0) {
+                               array_shift($result->output);
+                               if (!in_array($pool, $result->output)) {
+                                       $this->output = PoolError::MSG_ERROR_POOL_DOES_NOT_EXISTS;
+                                       $this->error = PoolError::ERROR_POOL_DOES_NOT_EXISTS;
+                                       return;
+                               }
+                       } else {
+                               $this->output = $result->output;
+                               $this->error = $result->exitcode;
+                               return;
+                       }
+               } else {
+                       $this->output = PoolError::MSG_ERROR_POOL_DOES_NOT_EXISTS;
+                       $this->error = PoolError::ERROR_POOL_DOES_NOT_EXISTS;
+                       return;
+               }
+
+               $cmd = array(
+                       'label',
+                       'volume="' . $volume . '"',
+                       'storage="' . $storage . '"',
+                       'drive="' . $drive . '"',
+                       'slot="' . $slot . '"',
+                       'pool="' . $pool . '"'
+               );
+               $result = $this->getModule('bconsole')->bconsoleCommand(
+                       $this->director,
+                       $cmd
+               );
+               if ($result->exitcode === 0) {
+                       $this->output = $result->output;
+                       $this->error = VolumeError::ERROR_NO_ERRORS;
+               } else {
+                       $this->output = $result->output;
+                       $this->error = $result->exitcode;
+               }
+       }
+}
+
+?>
diff --git a/gui/baculum/protected/API/Pages/API/VolumeLabelBarcodes.php b/gui/baculum/protected/API/Pages/API/VolumeLabelBarcodes.php
new file mode 100644 (file)
index 0000000..f7124f5
--- /dev/null
@@ -0,0 +1,124 @@
+<?php
+/*
+ * Bacula(R) - The Network Backup Solution
+ * Baculum   - Bacula web interface
+ *
+ * Copyright (C) 2013-2019 Kern Sibbald
+ *
+ * The main author of Baculum is Marcin Haba.
+ * The original author of Bacula is Kern Sibbald, with contributions
+ * from many others, a complete list can be found in the file AUTHORS.
+ *
+ * You may use this file and others of this release according to the
+ * license defined in the LICENSE file, which includes the Affero General
+ * Public License, v3.0 ("AGPLv3") and some additional permissions and
+ * terms pursuant to its AGPLv3 Section 7.
+ *
+ * This notice must be preserved when any source code is
+ * conveyed and/or propagated.
+ *
+ * Bacula(R) is a registered trademark of Kern Sibbald.
+ */
+
+Prado::using('Application.API.Class.Bconsole');
+
+class VolumeLabelBarcodes extends BaculumAPIServer {
+
+       public function create($params) {
+               $slots = property_exists($params, 'slots') ? $params->slots : 0;
+               $drive = property_exists($params, 'drive') ? intval($params->drive) : 0;
+               $poolid = property_exists($params, 'poolid') ? intval($params->poolid) : 0;
+               $misc = $this->getModule('misc');
+
+               $storage = null;
+               if (property_exists($params, 'storageid')) {
+                       $storageid = intval($params->storageid);
+                       $result = $this->getModule('storage')->getStorageById($storageid);
+                       if (is_object($result)) {
+                               $storage = $result->name;
+                       }
+               } elseif (property_exists($params, 'storage') && $misc->isValidName($params->storage)) {
+                       $storage = $params->storage;
+               }
+
+               $pool = null;
+               if (property_exists($params, 'poolid')) {
+                       $poolid = intval($params->poolid);
+                       $result = $this->getModule('pool')->getPoolById($poolid);
+                       if (is_object($result)) {
+                               $pool = $result->name;
+                       }
+               } elseif (property_exists($params, 'pool') && $misc->isValidName($params->pool)) {
+                       $pool = $params->pool;
+               }
+
+               if (!is_null($storage)) {
+                       $result = $this->getModule('bconsole')->bconsoleCommand(
+                               $this->director,
+                               array('.storage')
+                       );
+                       if ($result->exitcode === 0) {
+                               array_shift($result->output);
+                               if (!in_array($storage, $result->output)) {
+                                       $this->output = StorageError::MSG_ERROR_STORAGE_DOES_NOT_EXISTS;
+                                       $this->error = StorageError::ERROR_STORAGE_DOES_NOT_EXISTS;
+                                       return;
+                               }
+                       } else {
+                               $this->output = $result->output;
+                               $this->error = $result->exitcode;
+                               return;
+                       }
+               } else {
+                       $this->output = StorageError::MSG_ERROR_STORAGE_DOES_NOT_EXISTS;
+                       $this->error = StorageError::ERROR_STORAGE_DOES_NOT_EXISTS;
+                       return;
+               }
+
+               if (!is_null($pool)) {
+                       $result = $this->getModule('bconsole')->bconsoleCommand(
+                               $this->director,
+                               array('.pool')
+                       );
+                       if ($result->exitcode === 0) {
+                               array_shift($result->output);
+                               if (!in_array($pool, $result->output)) {
+                                       $this->output = PoolError::MSG_ERROR_POOL_DOES_NOT_EXISTS;
+                                       $this->error = PoolError::ERROR_POOL_DOES_NOT_EXISTS;
+                                       return;
+                               }
+                       } else {
+                               $this->output = $result->output;
+                               $this->error = $result->exitcode;
+                               return;
+                       }
+               } else {
+                       $this->output = PoolError::MSG_ERROR_POOL_DOES_NOT_EXISTS;
+                       $this->error = PoolError::ERROR_POOL_DOES_NOT_EXISTS;
+                       return;
+               }
+
+               $cmd = array (
+                       'label',
+                       'barcodes',
+                       'slots="' . $slots . '"',
+                       'storage="' . $storage . '"',
+                       'drive="' . $drive . '"',
+                       'pool="' . $pool . '"'
+               );
+               $result = $this->getModule('bconsole')->bconsoleCommand(
+                       $this->director,
+                       $cmd,
+                       Bconsole::PTYPE_CONFIRM_YES_CMD
+               );
+               if ($result->exitcode === 0) {
+                       $this->output = $result->output;
+                       $this->error = VolumeError::ERROR_NO_ERRORS;
+               } else {
+                       $this->output = $result->output;
+                       $this->error = $result->exitcode;
+               }
+       }
+}
+
+?>
index 4dbb0d8b3f44c195b01197b4cb734c6b03f0ea8f..31ea654edf339f064570571a8ac2967e96de47a2 100644 (file)
@@ -42,6 +42,8 @@
        <url ServiceParameter="API.VolumePurge" pattern="api/v1/volumes/{id}/purge/" parameters.id="\d+" />
        <url ServiceParameter="API.VolumesRequired" pattern="api/v1/volumes/required/{jobid}/{fileid}/" parameters.jobid="\d+" parameters.fileid="\d+" />
        <url ServiceParameter="API.JobsOnVolume" pattern="api/v1/volumes/{id}/jobs/" parameters.id="\d+" />
+       <url ServiceParameter="API.VolumeLabel" pattern="api/v1/volumes/label/" />
+       <url ServiceParameter="API.VolumeLabelBarcodes" pattern="api/v1/volumes/label/barcodes/" />
        <!-- pools endpoints -->
        <url ServiceParameter="API.Pools" pattern="api/v1/pools/" />
        <url ServiceParameter="API.Pool" pattern="api/v1/pools/{id}/" parameters.id="\d+" />
index dfaf702d84d106a1837b89bec6c431ff7fdde69c..87c3c32f8b2c17c9e2f3140201720bdf90b5c0b6 100644 (file)
@@ -74,8 +74,12 @@ class StorageError extends GenericError {
 
 class VolumeError extends GenericError {
        const ERROR_VOLUME_DOES_NOT_EXISTS = 30;
+       const ERROR_INVALID_VOLUME = 31;
+       const ERROR_INVALID_SLOT = 32;
 
        const MSG_ERROR_VOLUME_DOES_NOT_EXISTS = 'Volume does not exist.';
+       const MSG_ERROR_INVALID_VOLUME = 'Invalid volume.';
+       const MSG_ERROR_INVALID_SLOT = 'Invalid slot.';
 }
 
 class PoolError extends GenericError {
index 8a9ded6329ad1f8a1776f05a5caa037de419bccb..ad3d65cbcec96f9a639edeaf586a868c1c836d77 100644 (file)
@@ -239,6 +239,11 @@ class Miscellaneous extends TModule {
                return (preg_match('/^\d{4}-\d{2}-\d{2} \d{1,2}:\d{2}:\d{2}$/', $time) === 1);
        }
 
+       public function isValidRange($range) {
+               return (preg_match('/^[\d\-\,]+$/', $range) === 1);
+       }
+
+
        /**
         * Writing INI-style configuration file.
         *