|
|
This page is for people to post sample configurations for particularly
|
|
|
tricky or usefull setups. This can include unusual hardware setups, or
|
|
|
complicated schedules, for example.
|
|
|
|
|
|
## In the Debian manner
|
|
|
|
|
|
- Create a `conf.d` directory
|
|
|
|
|
|
```
|
|
|
mkdir /etc/bacula/conf.d
|
|
|
```
|
|
|
- Create one file per job
|
|
|
|
|
|
```
|
|
|
# vi /etc/bacula/conf.d/test.conf
|
|
|
|
|
|
Job {
|
|
|
Name = "Test"
|
|
|
Enabled = no
|
|
|
Client = backup-fd
|
|
|
FileSet = "FileSetTest"
|
|
|
Schedule = "ScheduleTest"
|
|
|
Write Bootstrap = "/var/bacula/Test.bsr"
|
|
|
Full Backup Pool = FullTest
|
|
|
Incremental Backup Pool = IncrTest
|
|
|
Differential Backup Pool = DiffTest
|
|
|
Storage = DAT72
|
|
|
Type = Backup
|
|
|
Level = Incremental
|
|
|
Pool = Default
|
|
|
Priority = 10
|
|
|
Messages = Standard
|
|
|
}
|
|
|
|
|
|
FileSet {
|
|
|
Name = "FileSetTest"
|
|
|
Include {
|
|
|
Options {
|
|
|
signature = MD5
|
|
|
}
|
|
|
File = /home
|
|
|
}
|
|
|
|
|
|
Exclude {
|
|
|
File = /proc
|
|
|
File = /tmp
|
|
|
File = /.journal
|
|
|
File = /.fsck
|
|
|
}
|
|
|
}
|
|
|
|
|
|
Schedule {
|
|
|
Name = "ScheduleTest"
|
|
|
Run = Full 1st sun at 23:05
|
|
|
Run = Differential 2nd-5th sun at 23:05
|
|
|
Run = Incremental mon-sat at 23:05
|
|
|
}
|
|
|
|
|
|
Pool {
|
|
|
Name = FullTest
|
|
|
Label Format = "FullTest"
|
|
|
Pool Type = Backup
|
|
|
Recycle = yes # Bacula can automatically recycle Volumes
|
|
|
AutoPrune = yes # Prune expired volumes
|
|
|
Volume Retention = 6 months
|
|
|
Maximum Volume Jobs = 1
|
|
|
}
|
|
|
|
|
|
Pool {
|
|
|
Name = DiffTest
|
|
|
Label Format = "DiffTest"
|
|
|
Pool Type = Backup
|
|
|
Recycle = yes
|
|
|
AutoPrune = yes
|
|
|
Volume Retention = 40 days
|
|
|
Maximum Volume Jobs = 1
|
|
|
}
|
|
|
|
|
|
Pool {
|
|
|
Name = IncrTest
|
|
|
Label Format = "IncrTest"
|
|
|
Pool Type = Backup
|
|
|
Recycle = yes
|
|
|
AutoPrune = yes
|
|
|
Volume Retention = 10 days
|
|
|
Maximum Volume Jobs = 1
|
|
|
}
|
|
|
|
|
|
- Include it in Bacula Director configuration file
|
|
|
|
|
|
```{=html}
|
|
|
|
|
|
```
|
|
|
# vi /etc/bacula/bacula-dir.conf
|
|
|
|
|
|
[snip]
|
|
|
...
|
|
|
AutoPrune = yes # Prune expired volumes
|
|
|
Volume Retention = 365 days # one year
|
|
|
MaximumVolumeBytes = 4700000000
|
|
|
}
|
|
|
|
|
|
#
|
|
|
# Restricted console used by tray-monitor to get the status of the director
|
|
|
#
|
|
|
Console {
|
|
|
Name = backup-mon
|
|
|
Password = "7f+4TYcZiZuSuPcAJQODTta55CL8lBPrj9MuYdyx6Y3u"
|
|
|
CommandACL = status, .status
|
|
|
}
|
|
|
|
|
|
# Include below all yours jobs configuration files (remember add '@' at beginning)
|
|
|
@/etc/bacula/conf.d/test.conf
|
|
|
|
|
|
### Sharing common configuration (a template approximation)
|
|
|
|
|
|
- Create a file with Schedule declaration
|
|
|
|
|
|
```{=html}
|
|
|
<!-- -->
|
|
|
```
|
|
|
# vi /etc/bacula/conf.d/schedule.conf
|
|
|
|
|
|
Run = Full on 1 at 23:05
|
|
|
Run = Differential thu at 23:05
|
|
|
Run = Incremental mon-fri at 3:05
|
|
|
|
|
|
- Include it in Schedule Resource declaration for each job file
|
|
|
|
|
|
```{=html}
|
|
|
<!-- -->
|
|
|
```
|
|
|
# vi /etc/bacula/conf.d/test.conf
|
|
|
|
|
|
[snip]
|
|
|
|
|
|
File = /.journal
|
|
|
File = /.fsck
|
|
|
}
|
|
|
}
|
|
|
|
|
|
Schedule {
|
|
|
Name = "ScheduleTest"
|
|
|
@/etc/bacula/conf.d/schedule.conf
|
|
|
}
|
|
|
|
|
|
Pool {
|
|
|
Name = FullTest
|
|
|
...
|
|
|
|
|
|
### Put Pools, Clients and Storages Resources in separated files
|
|
|
|
|
|
To maintain Bacula Director configuration file as clean as possible and
|
|
|
more readable, is a good idea put Pools, Clients and Storages Resources
|
|
|
declarations in different files.
|
|
|
|
|
|
For example:
|
|
|
|
|
|
- Put Pools declaration in a separated file
|
|
|
|
|
|
```{=html}
|
|
|
<!-- -->
|
|
|
```
|
|
|
# vi /etc/bacula/conf.d/pools.conf
|
|
|
|
|
|
Pool {
|
|
|
Name = AllIncrementals
|
|
|
Label Format = "Incr"
|
|
|
Pool Type = Backup
|
|
|
Recycle = yes # Bacula can automatically recycle Volumes
|
|
|
AutoPrune = yes # Prune expired volumes
|
|
|
Storage = DDS-4
|
|
|
Volume Retention = 2 months
|
|
|
}
|
|
|
|
|
|
Pool {
|
|
|
Name = AllDifferentials
|
|
|
Label Format = "Diff"
|
|
|
Pool Type = Backup
|
|
|
Recycle = yes # Bacula can automatically recycle Volumes
|
|
|
AutoPrune = yes # Prune expired volumes
|
|
|
Storage = DAT72
|
|
|
Volume Retention = 2 months
|
|
|
}
|
|
|
|
|
|
AllInrementals pool is used to backup all Incrementals jobs in the same
|
|
|
tape. Same idea with AllDifferentials pool.
|
|
|
|
|
|
Note: than don\'t exist \"Maximum Volume Jobs\" statement
|
|
|
|
|
|
- Include it in Bacula Director configuration file
|
|
|
|
|
|
```{=html}
|
|
|
<!-- -->
|
|
|
```
|
|
|
# vi /etc/bacula/bacula-dir.conf
|
|
|
|
|
|
[snip]
|
|
|
...
|
|
|
Password = "7f+4TYcZiZuSuPcAJQODTta55CL8lBPrj9MuYdyx6Y3u"
|
|
|
CommandACL = status, .status
|
|
|
}
|
|
|
|
|
|
# Include below all yours jobs configuration files (remember add '@' at beginning)
|
|
|
@/etc/bacula/conf.d/test.conf
|
|
|
|
|
|
# Pools definition files
|
|
|
@/etc/bacula/conf.d/pools.conf
|
|
|
|
|
|
A job file example than use those pools could be:
|
|
|
|
|
|
# vi /etc/bacula/conf.d/test.conf
|
|
|
|
|
|
Job {
|
|
|
Name = "Test"
|
|
|
Enabled = no
|
|
|
Client = backup-fd
|
|
|
FileSet = "FileSetTest"
|
|
|
Schedule = "ScheduleTest"
|
|
|
Write Bootstrap = "/var/bacula/Test.bsr"
|
|
|
Full Backup Pool = FullTest
|
|
|
Incremental Backup Pool = AllIncrementals
|
|
|
Differential Backup Pool = AllDifferentials
|
|
|
Storage = DAT72
|
|
|
Type = Backup
|
|
|
...
|
|
|
|
|
|
- Same way for Clients and Storage.
|
|
|
|
|
|
An Bacula Director configuration example could be:
|
|
|
|
|
|
# vi /etc/bacula/bacula-dir.conf
|
|
|
|
|
|
[snip]
|
|
|
...
|
|
|
AutoPrune = yes # Prune expired volumes
|
|
|
Volume Retention = 365 days # one year
|
|
|
MaximumVolumeBytes = 4700000000
|
|
|
}
|
|
|
|
|
|
#
|
|
|
# Restricted console used by tray-monitor to get the status of the director
|
|
|
#
|
|
|
Console {
|
|
|
Name = backup-mon
|
|
|
Password = "7f+4TYcZiZuSuPcAJQODTta55CL8lBPrj9MuYdyx6Y3u"
|
|
|
CommandACL = status, .status
|
|
|
}
|
|
|
|
|
|
# Include below all yours jobs configuration files (remember add '@' at beginning)
|
|
|
@/etc/bacula/conf.d/test.conf
|
|
|
@/etc/bacula/conf.d/mails.conf
|
|
|
@/etc/bacula/conf.d/server2.conf
|
|
|
@/etc/bacula/conf.d/monitor.conf
|
|
|
@/etc/bacula/conf.d/debian.conf
|
|
|
|
|
|
# Clients definition files
|
|
|
@/etc/bacula/conf.d/clients.conf
|
|
|
|
|
|
# Storages definition file
|
|
|
@/etc/bacula/conf.d/storages.conf
|
|
|
|
|
|
# Pools definition files
|
|
|
@/etc/bacula/conf.d/pools.conf
|
|
|
|
|
|
Since Bacula 2.2.0 you can include the output of a command within a
|
|
|
configuration file with the \"@\|\" syntax. Here\'s how you can use
|
|
|
\"@\|\" to include all files within some directory without explicitly
|
|
|
naming the files (this lets you, say, add new clients to a configuration
|
|
|
without changing existing configuration files, just by adding a file for
|
|
|
the new client, containing its Job, Client, and FileSet resources, to
|
|
|
the included directory):
|
|
|
|
|
|
#
|
|
|
# Include subfiles associated with configuration of clients.
|
|
|
# They define the bulk of the Clients, Jobs, and FileSets.
|
|
|
# Remember to "reload" the Director after adding a client file.
|
|
|
#
|
|
|
@|"find /etc/bacula/clientdefs -name '*.conf' -type f -exec echo @{} \;"
|
|
|
|
|
|
## Faking an auto-changer with one tape drive
|
|
|
|
|
|
After reading [Total Automation of Bacula Tape
|
|
|
Handling](http://www.bacula.org/en/rel-manual/Tips_Suggestions.html#SECTION0038160000000000000000)
|
|
|
tip in the Bacula manual, I eventually managed to get it to work with
|
|
|
the latest version of Bacula with a lot of script hacking.
|
|
|
|
|
|
Here\'s what I came up with\...
|
|
|
|
|
|
- Director config
|
|
|
|
|
|
```{=html}
|
|
|
<!-- -->
|
|
|
```
|
|
|
Storage {
|
|
|
Name = LTO-2
|
|
|
Address = storage.host.name
|
|
|
SDPort = 9103
|
|
|
Password = "storage_password"
|
|
|
Device = LTO-2
|
|
|
Media Type = LTO-2
|
|
|
Autochanger = yes
|
|
|
Maximum Concurrent Jobs = 5
|
|
|
}
|
|
|
|
|
|
- Storage Daemon Config
|
|
|
|
|
|
```{=html}
|
|
|
<!-- -->
|
|
|
```
|
|
|
Autochanger {
|
|
|
Name = LTO-2
|
|
|
Device = LTO-2-Drive
|
|
|
Changer Device = /dev/nst0
|
|
|
Changer Command = "/usr/local/bin/bacula-changer.sh %o %a %S"
|
|
|
}
|
|
|
|
|
|
Device {
|
|
|
Name = LTO-2-Drive
|
|
|
Drive Index = 0
|
|
|
Autochanger = yes
|
|
|
Archive Device = /dev/nst0
|
|
|
Maximum Changer Wait = 3d
|
|
|
AutomaticMount = yes
|
|
|
AlwaysOpen = yes
|
|
|
Media Type = LTO-2
|
|
|
RemovableMedia = yes
|
|
|
Offline On Unmount = no
|
|
|
Spool Directory = /home/bacula/spool
|
|
|
}
|
|
|
|
|
|
- /usr/local/bin/bacula-changer.sh script
|
|
|
|
|
|
```{=html}
|
|
|
<!-- -->
|
|
|
```
|
|
|
#!/bin/sh
|
|
|
#
|
|
|
# Bacula interface to mtx autoloader
|
|
|
#
|
|
|
# Created OCT/31/03 by Alexander Kuehn, derived from Ludwig Jaffe's script
|
|
|
#
|
|
|
# *Heavily* hacked between 31/10/07 & 02/11/07 by Sean Cardus to make it work
|
|
|
# with the current Bacula version & our LTO tape drive. This works for me,
|
|
|
# it might work for you too - But, don't blame me if it blows up :)
|
|
|
#
|
|
|
# John Murray added storagename feature on 6th Nov 2007 to cater for situation
|
|
|
# where more than one Storage resource exists - we need to supply the correct
|
|
|
# qualifier after 'status Storage'
|
|
|
#
|
|
|
# * Check that the bacula-sd process has permission to run this script,
|
|
|
# run bconsole and to write to the logfile specified below! *
|
|
|
#
|
|
|
#set -x
|
|
|
# these are the labels of the tapes in each virtual slot, not the slots!
|
|
|
labels="DC01 DC02 DC03 DC04 DC05 DC06 DC07 DC08 DC09 DC10"
|
|
|
|
|
|
# If more than one Storage resource exists, specify which to check status
|
|
|
# of (name is case-sensitive)
|
|
|
# e.g.
|
|
|
# storagename="Tape"
|
|
|
storagename=""
|
|
|
|
|
|
# who to send a mail to?
|
|
|
recipient=operator@my.domain.name
|
|
|
logfile=/var/log/mtx.log
|
|
|
|
|
|
# Delay in seconds how often to check whether a new tape has been inserted
|
|
|
TAPEDELAY=10 # the default is every 10 seconds
|
|
|
echo `date` ":" $@ >>$logfile
|
|
|
|
|
|
# change this if mt is not in the path (use different quotes!)
|
|
|
mt=`which mt`
|
|
|
grep=`which grep`
|
|
|
#
|
|
|
# how to run the console application?
|
|
|
console="/usr/sbin/bconsole -c /etc/bacula/bconsole.conf"
|
|
|
|
|
|
command="$1"
|
|
|
|
|
|
#TAPEDRIVE0 holds the device/name of your 1st and only drive (Bacula supports only 1 drive currently)
|
|
|
#Read TAPEDRIVE from command line parameters
|
|
|
if [ -z "$2" ] ; then
|
|
|
TAPEDRIVE0=/dev/nst0
|
|
|
else
|
|
|
TAPEDRIVE0=$2
|
|
|
fi
|
|
|
|
|
|
#Read slot from command line parameters
|
|
|
if [ -z "$3" ] ; then
|
|
|
slot=`expr 1`
|
|
|
else
|
|
|
slot=`expr $3`
|
|
|
fi
|
|
|
|
|
|
if [ -z "$command" ] ; then
|
|
|
echo ""
|
|
|
echo "The mtx-changer script for Bacula"
|
|
|
echo "---------------------------------"
|
|
|
echo ""
|
|
|
echo "usage: mtx-changer <command> <devicename of tapedrive> [slot]"
|
|
|
echo " mtx-changer"
|
|
|
echo ""
|
|
|
echo "Valid commands:"
|
|
|
echo ""
|
|
|
echo "unload Unloads a tape into the slot"
|
|
|
echo " from where it was loaded."
|
|
|
echo "load <slot> Loads a tape from the slot <slot>"
|
|
|
echo "list Lists full storage slots"
|
|
|
echo "loaded Gives slot from where the tape was loaded."
|
|
|
echo " 0 means the tape drive is empty."
|
|
|
echo "slots Gives Number of avialable slots."
|
|
|
echo "volumes List avialable slots and the label of the."
|
|
|
echo " tape in it (slot:volume)"
|
|
|
echo "Example:"
|
|
|
echo " mtx-changer load /dev/nst0 1 loads a tape from slot1"
|
|
|
echo " mtx-changer %a %o %S "
|
|
|
echo ""
|
|
|
exit 0
|
|
|
fi
|
|
|
|
|
|
case "$command" in
|
|
|
unload)
|
|
|
echo "mtx-changer: Unload request on $TAPEDRIVE0" >>$logfile
|
|
|
|
|
|
DRIVESTATUS=`$mt -f $TAPEDRIVE0 status | grep ONLINE`
|
|
|
echo "DriveStatus: $DRIVESTATUS" >>$logfile
|
|
|
if [ -z $DRIVESTATUS ] ; then
|
|
|
echo "Drive is OFFLINE" >>$logfile
|
|
|
else
|
|
|
echo "Drive is ONLINE" >>$logfile
|
|
|
echo "Taking drive offline and ejecting..." >>$logfile
|
|
|
mt -f $TAPEDRIVE0 rewoffl 2>/dev/null
|
|
|
fi
|
|
|
|
|
|
exit 0
|
|
|
;;
|
|
|
|
|
|
load)
|
|
|
echo "mtx-changer: load request on $TAPEDRIVE0" >>$logfile
|
|
|
|
|
|
#Let's check if drive is loaded before we load it
|
|
|
MOUNTED=`echo "status Storage=$storagename" | $console | $grep $TAPEDRIVE0 | $grep "is mounted with"`
|
|
|
if [ -z "$MOUNTED" ] ; then
|
|
|
echo "Drive is UNMOUNTED: $MOUNTED" >>$logfile
|
|
|
else
|
|
|
echo "Drive is MOUNTED: $MOUNTED" >>$logfile
|
|
|
VOLUME=`echo "status Storage=$storagename" | $console | $grep -A2 $TAPEDRIVE0 | $grep "Volume:" | awk {'print $2'}`
|
|
|
echo "Mounted Volume: $VOLUME" >>$logfile
|
|
|
if [ $MOUNTED = $3 ] ; then
|
|
|
echo "$3 is already mounted in $TAPEDRIVE0 as $VOLUME" >>$logfile
|
|
|
exit
|
|
|
else
|
|
|
echo "$VOLUME is currently mounted in $TAPEDRIVE0, unmounting..." >>$logfile
|
|
|
echo "unmount" | $console >/dev/null 2>/dev/null
|
|
|
fi
|
|
|
fi
|
|
|
|
|
|
echo "Taking drive offline and ejecting..." >>$logfile
|
|
|
mt -f $TAPEDRIVE0 rewoffl 2>/dev/null
|
|
|
|
|
|
# extract label for the mail
|
|
|
count=`expr 1`
|
|
|
for label in $labels ; do
|
|
|
if [ $slot -eq $count ] ; then volume=$label ; fi
|
|
|
count=`expr $count + 1`
|
|
|
done
|
|
|
|
|
|
mail -s "Bacula needs volume $volume." $recipient <<END_OF_DATA
|
|
|
Please insert tape labelled $volume from slot $slot into $TAPEDRIVE0.
|
|
|
Kind regards,
|
|
|
Bacula.
|
|
|
END_OF_DATA
|
|
|
|
|
|
sleep $TAPEDELAY
|
|
|
|
|
|
# Wait for the tape to be inserted
|
|
|
STATUS=`$mt -f $TAPEDRIVE0 status | $grep ONLINE`
|
|
|
while [ -z "$STATUS" ] ; do
|
|
|
sleep $TAPEDELAY
|
|
|
STATUS=`$mt -f $TAPEDRIVE0 status | $grep ONLINE`
|
|
|
done
|
|
|
|
|
|
mail -s "Bacula says thank you." $recipient <<END_OF_DATA
|
|
|
Thank you for inserting the new tape! (I requested volume $volume from slot $slot.)
|
|
|
Kind regards,
|
|
|
Bacula.
|
|
|
END_OF_DATA
|
|
|
|
|
|
echo "Successfully loaded a tape into drive $TAPEDRIVE0 (requested $volume from slot $slot)." >>$logfile
|
|
|
echo "Loading finished." ; >>$logfile
|
|
|
echo "$slot"
|
|
|
exit 0
|
|
|
;;
|
|
|
|
|
|
list)
|
|
|
echo "mtx-changer: Requested list" >>$logfile
|
|
|
count=`expr 1`
|
|
|
for label in $labels ; do
|
|
|
echo $count:$label
|
|
|
count=`expr $count + 1`
|
|
|
done
|
|
|
printf "\n"
|
|
|
;;
|
|
|
|
|
|
loaded)
|
|
|
echo "mtx-changer: tape loaded request on $TAPEDRIVE0" >>$logfile
|
|
|
|
|
|
DRIVESTATUS=`mt -f $TAPEDRIVE0 status 2>/dev/null`
|
|
|
MTRTN=$?
|
|
|
if [ $MTRTN = "0" ] ; then
|
|
|
echo "MT ran ok. Return Code: $MTRTN" >>$logfile
|
|
|
DRIVESTATUS=`mt -f $TAPEDRIVE0 status | grep "DR_OPEN"`
|
|
|
if [ -z "$DRIVESTATUS"] ; then
|
|
|
echo "MT says the drive has a tape" >>$logfile
|
|
|
echo "0"
|
|
|
else
|
|
|
echo "MT says the drive is empty" >>$logfile
|
|
|
echo "0"
|
|
|
fi
|
|
|
else
|
|
|
echo "MT error, bacula might be using it! Return code: $MTRTN" >>$logfile
|
|
|
|
|
|
MOUNTED=`echo "status Storage=$storagename" | $console | $grep $TAPEDRIVE0 | $grep "is mounted with"`
|
|
|
if [ -z "$MOUNTED" ] ; then
|
|
|
echo "Drive is UNMOUNTED: $MOUNTED">>$logfile
|
|
|
echo "0"
|
|
|
else
|
|
|
echo "Drive is MOUNTED: $MOUNTED">>$logfile
|
|
|
VOLUME=`echo "status Storage=$storagename" | $console | $grep -A2 $TAPEDRIVE0 | $grep "Volume:" | awk {'print $2'}`
|
|
|
echo "Mounted Volume: $VOLUME" >>$logfile
|
|
|
count=`expr 1`
|
|
|
for label in $labels ; do
|
|
|
if [ $VOLUME = $label ] ; then
|
|
|
echo "$VOLUME = $label in slot $count" >>$logfile
|
|
|
echo "$count"
|
|
|
fi
|
|
|
count=`expr $count + 1`
|
|
|
done
|
|
|
fi
|
|
|
fi
|
|
|
exit 0
|
|
|
;;
|
|
|
|
|
|
slots)
|
|
|
echo "mtx-changer: Request slots" >>$logfile
|
|
|
count=`expr 0`
|
|
|
for label in $labels ; do
|
|
|
count=`expr $count + 1`
|
|
|
done
|
|
|
echo $count
|
|
|
;;
|
|
|
|
|
|
volumes)
|
|
|
echo "mtx-changer: Request volumes" >>$logfile
|
|
|
count=`expr 1`
|
|
|
for label in $labels ; do
|
|
|
printf "$count:$label"
|
|
|
count=`expr $count + 1`
|
|
|
done
|
|
|
printf "\n"
|
|
|
;;
|
|
|
esac
|
|
|
|
|
|
## SD Configuration for Bacula with two one-drive auto changers
|
|
|
|
|
|
Autochanger {
|
|
|
Name = Autochanger1
|
|
|
Device = Drive-1
|
|
|
Changer Command = "/etc/bacula/mtx-changer %c %o %S %a %d"
|
|
|
Changer Device = /dev/sg0
|
|
|
}
|
|
|
|
|
|
Autochanger {
|
|
|
Name = Autochanger2
|
|
|
Device = Drive-2
|
|
|
Changer Command = "/etc/bacula/mtx-changer %c %o %S %a %d"
|
|
|
Changer Device = /dev/sg1
|
|
|
}
|
|
|
|
|
|
Device {
|
|
|
Name = Drive-1 #
|
|
|
Drive Index = 0
|
|
|
Media Type = LTO-2
|
|
|
Archive Device = /dev/st0
|
|
|
Changer Device = /dev/sg0
|
|
|
AutomaticMount = yes; # when device opened, read it
|
|
|
AlwaysOpen = yes;
|
|
|
RemovableMedia = yes;
|
|
|
RandomAccess = no;
|
|
|
AutoChanger = yes
|
|
|
Label Media = no
|
|
|
# Enable the Alert command only if you have the mtx package loaded
|
|
|
Alert Command = "sh -c 'tapeinfo -f %c |grep TapeAlert|cat'"
|
|
|
}
|
|
|
|
|
|
Device {
|
|
|
Name = Drive-2 #
|
|
|
Drive Index = 0
|
|
|
Media Type = LTO-2
|
|
|
Archive Device = /dev/st1
|
|
|
Changer Device = /dev/sg1
|
|
|
AutomaticMount = yes; # when device opened, read it
|
|
|
AlwaysOpen = yes;
|
|
|
RemovableMedia = yes;
|
|
|
RandomAccess = no;
|
|
|
AutoChanger = yes
|
|
|
Label Media = no
|
|
|
# Enable the Alert command only if you have the mtx package loaded
|
|
|
Alert Command = "sh -c 'tapeinfo -f %c |grep TapeAlert|cat'"
|
|
|
}
|
|
|
|
|
|
## Dell ML6000 Configuration
|
|
|
|
|
|
Autochanger and device resources for an ML6000 with two LTO-3 drives
|
|
|
(includes some commented-out default values):
|
|
|
|
|
|
Autochanger {
|
|
|
Name = "ML6000 Library"
|
|
|
Device = ML6000-LTO3-0, ML6000-LTO3-1
|
|
|
Changer Device = /dev/sg3
|
|
|
Changer Command = "/usr/local/bacula/sbin/mtx-changer %c %o %S %a %d"
|
|
|
# %c = changer device
|
|
|
# %o = command (unload|load|loaded|list|slots)
|
|
|
# %S = slot index (1-based)
|
|
|
# %a = archive device (i.e., /dev/sd* name for tape drive)
|
|
|
# %d = drive index (0-based)
|
|
|
}
|
|
|
|
|
|
Device {
|
|
|
# The ML6000's first tape drive
|
|
|
Name = ML6000-LTO3-0
|
|
|
Archive Device = /dev/nst1
|
|
|
Device Type = Tape
|
|
|
Media Type = LTO3 # If we were likely to ever have
|
|
|
# multiple storage daemons
|
|
|
# with LTO3 drives, we might
|
|
|
# need to use media types like
|
|
|
# "ML6000-LTO3" to distinguish
|
|
|
# which library contained
|
|
|
# which volumes. But we're not.
|
|
|
Autochanger = Yes
|
|
|
# Changer Device = <inherited from Changer>
|
|
|
Alert Command = "sh -c '/usr/local/bacula/sbin/tapeinfo -f /dev/sg1 | /bin/sed -n /TapeAlert/p'"
|
|
|
# We use /dev/sg1 instead of
|
|
|
# %c because we want the tape
|
|
|
# drive's status, not the
|
|
|
# changer's. We use sed
|
|
|
# instead of grep to avoid
|
|
|
# logging non-zero exit
|
|
|
# status reports from
|
|
|
# grep when no strings
|
|
|
# match its pattern.
|
|
|
Drive Index = 0
|
|
|
# Autoselect = yes # Since our backup host lacks
|
|
|
# the I/O bandwidth for it to
|
|
|
# worthwhile to write to two
|
|
|
# drives simultaneously, it
|
|
|
# might be worthwhile
|
|
|
# manipulating this to either
|
|
|
# reserve a drive for
|
|
|
# restores, or to spread the
|
|
|
# wear across the two drives.
|
|
|
# Maximum Changer Wait = 300 seconds
|
|
|
# Maximum Rewind Wait = 300 seconds
|
|
|
# Maximum Open Wait = 300 seconds
|
|
|
# Always Open = Yes
|
|
|
# Volume Poll Interval = 0 # 0 means "don't poll".
|
|
|
RemovableMedia = yes
|
|
|
Random Access = no
|
|
|
# Maximum block size = 64512 # Some sources suggest 128K or
|
|
|
# 256K for better LTO3 throughput
|
|
|
# Hardware End of Medium = Yes
|
|
|
# Fast Forward Space File = Yes
|
|
|
# Use MTIOCGET = Yes
|
|
|
# BSF at EOM = No
|
|
|
# Two EOM = No
|
|
|
# Backward Space Record = Yes
|
|
|
# Backward Space File = Yes
|
|
|
# Forward Space Record = Yes
|
|
|
# Forward Space File = Yes
|
|
|
# Offline On Unmount = No
|
|
|
# Maximum File Size = 1gb
|
|
|
# Block Positioning = yes
|
|
|
# Maximum Network Buffer Size = 32768 # The manual suggests it may be
|
|
|
# worthwhile doubling this.
|
|
|
Maximum Spool Size = 100gb
|
|
|
Maximum Job Spool Size = 60gb
|
|
|
Spool Directory = /backup/spool
|
|
|
# Label media = No
|
|
|
# Automatic mount = Yes
|
|
|
}
|
|
|
|
|
|
Device {
|
|
|
# The ML6000's second tape drive
|
|
|
Name = ML6000-LTO3-1
|
|
|
Archive Device = /dev/nst2
|
|
|
Device Type = Tape
|
|
|
Media Type = LTO3
|
|
|
Autochanger = Yes
|
|
|
# Changer Device = <inherited from Changer>
|
|
|
Alert Command = "sh -c '/usr/local/bacula/sbin/tapeinfo -f /dev/sg2 | /bin/sed -n /TapeAlert/p"
|
|
|
Drive Index = 1
|
|
|
RemovableMedia = yes
|
|
|
Random Access = no
|
|
|
|
|
|
Maximum Spool Size = 80gb
|
|
|
Maximum Job Spool Size = 40gb
|
|
|
Spool Directory = /backup/spool
|
|
|
}
|
|
|
|
|
|
## (SUN) Storagetek SL-500 mtx-changer script
|
|
|
|
|
|
Inserted a new parameter in config file.
|
|
|
|
|
|
**\# If you vant Import/Export slots to show up in Bacula\
|
|
|
io_slots_visible=1 **
|
|
|
|
|
|
* mtx-changer.conf
|
|
|
|
|
|
# Bacula version 5.0.3
|
|
|
#
|
|
|
# This file is sourced by the mtx-changer script every time it runs.
|
|
|
# You can put your site customization here, and when you do an
|
|
|
# upgrade, the process should not modify this file. Thus you
|
|
|
# preserve your mtx-changer configuration.
|
|
|
#
|
|
|
|
|
|
# Set to 1 if you want to do offline before unload
|
|
|
offline=0
|
|
|
|
|
|
# Set to amount of time in seconds to wait after an offline
|
|
|
offline_sleep=0
|
|
|
|
|
|
# Set to amount of time in seconds to wait after a load
|
|
|
load_sleep=0
|
|
|
|
|
|
# Set to 1 to do an inventory before a status. Not normally needed.
|
|
|
inventory=0
|
|
|
|
|
|
# If you have a VXA PacketLoader, it might display a different
|
|
|
# Storage Element line, so try setting the following to 1
|
|
|
vxa_packetloader=0
|
|
|
|
|
|
# If you vant Import/Export slots to show up in Bacula
|
|
|
io_slots_visible=1
|
|
|
|
|
|
# Set to 1 if you want debug info written to a log
|
|
|
debug_log=0
|
|
|
|
|
|
|
|
|
# mt status output
|
|
|
# SunOS No Additional Sense
|
|
|
# FreeBSD Current Driver State: at rest.
|
|
|
# Linux ONLINE
|
|
|
# Note Debian has a different mt than the standard Linux version.
|
|
|
# When no tape is in the drive it waits 2 minutes.
|
|
|
# When a tape is in the drive, it prints user unfriendly output.
|
|
|
# Note, with Ubuntu Gusty (8.04), there are two versions of mt,
|
|
|
# so we attempt to figure out which one.
|
|
|
#
|
|
|
|
|
|
OS=`uname`
|
|
|
case ${OS} in
|
|
|
SunOS)
|
|
|
ready="No Additional Sense"
|
|
|
;;
|
|
|
FreeBSD)
|
|
|
ready="Current Driver State: at rest."
|
|
|
;;
|
|
|
Linux)
|
|
|
ready="ONLINE"
|
|
|
if test -f /etc/debian_version ; then
|
|
|
mt --version|grep "mt-st" >/dev/null 2>&1
|
|
|
if test $? -eq 1 ; then
|
|
|
ready="drive status"
|
|
|
fi
|
|
|
fi
|
|
|
;;
|
|
|
esac
|
|
|
|
|
|
* mtx-changer
|
|
|
|
|
|
#!/bin/sh
|
|
|
#
|
|
|
# Bacula interface to mtx autoloader
|
|
|
# Bacula version 5.0.3
|
|
|
#
|
|
|
# If you set in your Device resource
|
|
|
#
|
|
|
# Changer Command = "path-to-this-script/mtx-changer %c %o %S %a %d"
|
|
|
# you will have the following input to this script:
|
|
|
#
|
|
|
# So Bacula will always call with all the following arguments, even though
|
|
|
# in come cases, not all are used.
|
|
|
#
|
|
|
# mtx-changer "changer-device" "command" "slot" "archive-device" "drive-index"
|
|
|
# $1 $2 $3 $4 $5
|
|
|
#
|
|
|
# for example:
|
|
|
#
|
|
|
# mtx-changer /dev/sg0 load 1 /dev/nst0 0 (on a Linux system)
|
|
|
#
|
|
|
# will request to load the first cartidge into drive 0, where
|
|
|
# the SCSI control channel is /dev/sg0, and the read/write device
|
|
|
# is /dev/nst0.
|
|
|
#
|
|
|
# The commands are:
|
|
|
# Command Function
|
|
|
# unload unload a given slot
|
|
|
# load load a given slot
|
|
|
# loaded which slot is loaded?
|
|
|
# list list Volume names (requires barcode reader)
|
|
|
# slots how many slots total?
|
|
|
# listall list all info
|
|
|
# transfer
|
|
|
#
|
|
|
# Slots are numbered from 1 ...
|
|
|
# Drives are numbered from 0 ...
|
|
|
#
|
|
|
#
|
|
|
# If you need to an offline, refer to the drive as $4
|
|
|
# e.g. mt -f $4 offline
|
|
|
#
|
|
|
# Many changers need an offline after the unload. Also many
|
|
|
# changers need a sleep 60 after the mtx load.
|
|
|
#
|
|
|
# N.B. If you change the script, take care to return either
|
|
|
# the mtx exit code or a 0. If the script exits with a non-zero
|
|
|
# exit code, Bacula will assume the request failed.
|
|
|
#
|
|
|
|
|
|
# source our conf file
|
|
|
if test ! -f /etc/bacula/mtx-changer.conf ; then
|
|
|
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
|
|
echo "ERROR: /etc/bacula/mtx-changer.conf file not found!!!!"
|
|
|
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
|
|
exit 1
|
|
|
fi
|
|
|
. /etc/bacula/mtx-changer.conf
|
|
|
|
|
|
MTX=/opt/csw/sbin/mtx
|
|
|
|
|
|
if test ${debug_log} -ne 0 ; then
|
|
|
touch /var/bacula/working/mtx.log
|
|
|
fi
|
|
|
dbgfile="/var/bacula/working/mtx.log"
|
|
|
debug() {
|
|
|
if test -f $dbgfile; then
|
|
|
echo "`date +\"%Y%m%d-%H:%M:%S\"` $*" >> $dbgfile
|
|
|
fi
|
|
|
}
|
|
|
|
|
|
|
|
|
#
|
|
|
# Create a temporary file
|
|
|
#
|
|
|
make_temp_file() {
|
|
|
TMPFILE=`mktemp /var/bacula/working/mtx.XXXXXXXXXX`
|
|
|
if test x${TMPFILE} = x; then
|
|
|
TMPFILE="/var/bacula/working/mtx.$$"
|
|
|
if test -f ${TMPFILE}; then
|
|
|
echo "ERROR: Temp file security problem on: ${TMPFILE}"
|
|
|
exit 1
|
|
|
fi
|
|
|
fi
|
|
|
}
|
|
|
|
|
|
#
|
|
|
# The purpose of this function to wait a maximum
|
|
|
# time for the drive. It will
|
|
|
# return as soon as the drive is ready, or after
|
|
|
# waiting a maximum of 300 seconds.
|
|
|
# Note, this is very system dependent, so if you are
|
|
|
# not running on Linux, you will probably need to
|
|
|
# re-write it, or at least change the grep target.
|
|
|
# We've attempted to get the appropriate OS grep targets
|
|
|
# in the code at the top of this script.
|
|
|
#
|
|
|
wait_for_drive() {
|
|
|
i=0
|
|
|
while [ $i -le 300 ]; do # Wait max 300 seconds
|
|
|
if mt -f $1 status 2>&1 | grep "${ready}" >/dev/null 2>&1; then
|
|
|
break
|
|
|
fi
|
|
|
debug "Device $1 - not ready, retrying..."
|
|
|
sleep 1
|
|
|
i=`expr $i + 1`
|
|
|
done
|
|
|
}
|
|
|
|
|
|
# check parameter count on commandline
|
|
|
#
|
|
|
check_parm_count() {
|
|
|
pCount=$1
|
|
|
pCountNeed=$2
|
|
|
if test $pCount -lt $pCountNeed; then
|
|
|
echo "ERROR: usage: mtx-changer ctl-device command [slot archive-device drive-index]"
|
|
|
echo " Insufficient number of arguments given."
|
|
|
if test $pCount -lt 2; then
|
|
|
echo " Mimimum usage is first two arguments ..."
|
|
|
else
|
|
|
echo " Command expected $pCountNeed arguments"
|
|
|
fi
|
|
|
exit 1
|
|
|
fi
|
|
|
}
|
|
|
|
|
|
# Check for special cases where only 2 arguments are needed,
|
|
|
# all others are a minimum of 5
|
|
|
#
|
|
|
case $2 in
|
|
|
list|listall)
|
|
|
check_parm_count $# 2
|
|
|
;;
|
|
|
slots)
|
|
|
check_parm_count $# 2
|
|
|
;;
|
|
|
transfer)
|
|
|
check_parm_count $# 4
|
|
|
;;
|
|
|
*)
|
|
|
check_parm_count $# 5
|
|
|
;;
|
|
|
esac
|
|
|
|
|
|
|
|
|
# Setup arguments
|
|
|
ctl=$1
|
|
|
cmd="$2"
|
|
|
slot=$3
|
|
|
device=$4
|
|
|
drive=$5
|
|
|
|
|
|
debug "Parms: $ctl $cmd $slot $device $drive"
|
|
|
|
|
|
case $cmd in
|
|
|
unload)
|
|
|
debug "Doing mtx -f $ctl unload $slot $drive"
|
|
|
|
|
|
if test ${offline} -eq 1 ; then
|
|
|
mt -f $device offline
|
|
|
fi
|
|
|
if test ${offline_sleep} -ne 0 ; then
|
|
|
sleep ${offline_sleep}
|
|
|
fi
|
|
|
${MTX} -f $ctl unload $slot $drive
|
|
|
;;
|
|
|
|
|
|
load)
|
|
|
debug "Doing mtx -f $ctl load $slot $drive"
|
|
|
${MTX} -f $ctl load $slot $drive
|
|
|
rtn=$?
|
|
|
if test ${load_sleep} -ne 0 ; then
|
|
|
sleep ${load_sleep}
|
|
|
fi
|
|
|
wait_for_drive $device
|
|
|
exit $rtn
|
|
|
;;
|
|
|
|
|
|
list)
|
|
|
debug "Doing mtx -f $ctl -- to list volumes"
|
|
|
make_temp_file
|
|
|
if test ${inventory} -ne 0 ; then
|
|
|
${MTX} -f $ctl inventory
|
|
|
fi
|
|
|
${MTX} -f $ctl status >${TMPFILE}
|
|
|
rtn=$?
|
|
|
if test ${vxa_packetloader} -ne 0 ; then
|
|
|
cat ${TMPFILE} | grep " *Storage Element [0-9]*:.*Full" | sed "s/ Storage Element //" | sed "s/Full :VolumeTag=//"
|
|
|
else
|
|
|
if test ${io_slots_visible} -ne 0 ; then
|
|
|
cat ${TMPFILE} | grep " Storage Element [0-9]*.*:Full.*" | sed "s/ *IMPORT\/EXPORT//" | awk "{print \$3 \$4}" | sed "s/Full.*:VolumeTag=//"
|
|
|
else
|
|
|
cat ${TMPFILE} | grep " *Storage Element [0-9]*:.*Full" | awk "{print \$3 \$4}" | sed "s/Full.*:VolumeTag=//"
|
|
|
fi
|
|
|
fi
|
|
|
cat ${TMPFILE} | grep "^Data Transfer Element [0-9]*:Full (Storage Element [0-9]" | awk '{printf "%s:%s\n",$7,$10}'
|
|
|
rm -f ${TMPFILE} >/dev/null 2>&1
|
|
|
exit $rtn
|
|
|
;;
|
|
|
|
|
|
listall)
|
|
|
# Drive content: D:Drive num:F:Slot loaded:Volume Name
|
|
|
# D:0:F:2:vol2 or D:Drive num:E
|
|
|
# D:1:F:42:vol42
|
|
|
# D:3:E
|
|
|
#
|
|
|
# Slot content:
|
|
|
# S:1:F:vol1 S:Slot num:F:Volume Name
|
|
|
# S:2:E or S:Slot num:E
|
|
|
# S:3:F:vol4
|
|
|
#
|
|
|
# Import/Export tray slots:
|
|
|
# I:10:F:vol10 I:Slot num:F:Volume Name
|
|
|
# I:11:E or I:Slot num:E
|
|
|
# I:12:F:vol40
|
|
|
|
|
|
debug "Doing mtx -f $ctl -- to list all"
|
|
|
make_temp_file
|
|
|
if test ${inventory} -ne 0 ; then
|
|
|
${MTX} -f $ctl inventory
|
|
|
fi
|
|
|
${MTX} -f $ctl status >${TMPFILE}
|
|
|
rtn=$?
|
|
|
# can be converted to awk+sed+cut, see below
|
|
|
# perl -ne '
|
|
|
#/Data Transfer Element (\d+):Empty/ && print "D:$1:E\n";
|
|
|
#/Data Transfer Element (\d+):Full \(Storage Element (\d+) Loaded\)(:VolumeTag =\s*(.+))?/ && print "D:$1:F:$2:$4\n";
|
|
|
#/Storage Element (\d+):Empty/ && print "S:$1:E\n";
|
|
|
#/Storage Element (\d+):Full( :VolumeTag=(.+))?/ && print "S:$1:F:$3\n";
|
|
|
#/Storage Element (\d+) IMPORT.EXPORT:Empty/ && print "I:$1:E\n";
|
|
|
#/Storage Element (\d+) IMPORT.EXPORT:Full( :VolumeTag=(.+))?/ && print "I:$1:F:$3\n";' ${TMPFILE}
|
|
|
# If perl isn't installed, you can use by those commands
|
|
|
cat ${TMPFILE} | grep "Data Transfer Element" | awk "{print \"D:\"\$4 \$7 \$9 \$10}" | sed "s/=/:/" | sed "s/Full/F:/" | sed "s/Empty/E/"
|
|
|
cat ${TMPFILE} | grep -v "Data Transfer Element" | grep "Storage Element" | grep -v "IMPORT/EXPORT" | awk "{print \"S:\"\$3 \$4 \$5}" | sed "s/IMPORT\/EXPORT//" | sed "s/Full *:VolumeTag=/F:/" | sed "s/Empty/E/"
|
|
|
cat ${TMPFILE} | grep -v "Data Transfer Element" | grep "Storage Element" | grep "IMPORT/EXPORT" | awk "{print \"I:\"\$3 \$4 \$5}" | sed "s/IMPORT\/EXPORT//" | sed "s/Full *:VolumeTag=/F:/" | sed "s/Empty/E/"
|
|
|
|
|
|
rm -f ${TMPFILE} >/dev/null 2>&1
|
|
|
exit $rtn
|
|
|
;;
|
|
|
|
|
|
transfer)
|
|
|
slotdest=$device
|
|
|
debug "Doing transfer from $slot to $slotdest"
|
|
|
${MTX} -f $ctl transfer $slot $slotdest
|
|
|
rtn=$?
|
|
|
exit $rtn
|
|
|
;;
|
|
|
|
|
|
loaded)
|
|
|
debug "Doing mtx -f $ctl $drive -- to find what is loaded"
|
|
|
make_temp_file
|
|
|
${MTX} -f $ctl status >${TMPFILE}
|
|
|
rtn=$?
|
|
|
cat ${TMPFILE} | grep "^Data Transfer Element $drive:Full" | awk "{print \$7}"
|
|
|
cat ${TMPFILE} | grep "^Data Transfer Element $drive:Empty" | awk "{print 0}"
|
|
|
rm -f ${TMPFILE} >/dev/null 2>&1
|
|
|
exit $rtn
|
|
|
;;
|
|
|
|
|
|
slots)
|
|
|
debug "Doing mtx -f $ctl -- to get count of slots"
|
|
|
${MTX} -f $ctl status | grep " *Storage Changer" | awk "{print \$5}"
|
|
|
;;
|
|
|
esac |