Difference between revisions of "Bacula and Bareos"
(→Configure On CentOS 6.5) |
(→Configure On CentOS 6.5) |
||
Line 32: | Line 32: | ||
nano /etc/bareos/vchanger | nano /etc/bareos/vchanger | ||
− | [[ | + | </pre> |
+ | |||
+ | |||
+ | #!/bin/sh | ||
+ | # | ||
+ | # Bacula interface to virtual autochanger using removable disk drives | ||
+ | # | ||
+ | # Based (somewhat) on the "disk-changer" script from bacula 1.39.26 | ||
+ | # | ||
+ | # Vchanger is a Bacula autochanger script that emulates a conventional | ||
+ | # magazine-based tape library device using removable disk drives. | ||
+ | # Partitions on the removable drives are used as virtual magazines, | ||
+ | # where each "magazine" contains the same number of virtual slots. Each | ||
+ | # "slot" holds one virtual tape, where a "tape" is a regular file that | ||
+ | # Bacula treats as a "Device Type = File" volume. | ||
+ | # | ||
+ | # This script will be invoked by Bacula using the Bacula Autochanger | ||
+ | # Interface and will be passed the following arguments: | ||
+ | # | ||
+ | # vchanger "changer-device" "command" "slot" "archive-device" "drive-index" | ||
+ | # $1 $2 $3 #4 #5 | ||
+ | # | ||
+ | # See the Bacula documentation and the Bacula Removable Disk Howto for | ||
+ | # further details. | ||
+ | # | ||
+ | # Copyright (C) 2006 Josh Fisher | ||
+ | # | ||
+ | # Permission to use, copy, modify, distribute, and sell this software | ||
+ | # and its documentation for any purpose is hereby granted without fee, | ||
+ | # provided that the above copyright notice appear in all copies. This | ||
+ | # software is provided "as is" without express or implied warranty. | ||
+ | # | ||
+ | # This software is distributed in the hope that it will be useful, | ||
+ | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
+ | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
+ | # | ||
+ | # $Id: vchanger,v 0.7.4 2006/12/01 09:29:04 jfisher Exp $ | ||
+ | |||
+ | # | ||
+ | # log whats done | ||
+ | # | ||
+ | # to turn on logging, uncomment the following line | ||
+ | #touch $wd/vchanger.log | ||
+ | # | ||
+ | |||
+ | # | ||
+ | # Write to a log file | ||
+ | # To log debugging info, create file /var/bacula/vchanger.log | ||
+ | # with write permission for bacula-sd user. To stop logging, | ||
+ | # delete file /var/bacula/vchanger.log | ||
+ | # | ||
+ | dbgfile="/var/bacula/vchanger.log" | ||
+ | function debug() | ||
+ | { | ||
+ | if test -e $dbgfile; then | ||
+ | echo "`date +\"%Y%m%d-%H:%M:%S\"` $*" >> $dbgfile | ||
+ | fi | ||
+ | } | ||
+ | |||
+ | # | ||
+ | # Return length of string $1 | ||
+ | # | ||
+ | if [ `uname` = "FreeBSD" ] | ||
+ | then | ||
+ | function strlen () | ||
+ | { | ||
+ | expr -- "$1" : ".*" | ||
+ | } | ||
+ | else | ||
+ | function strlen () | ||
+ | { | ||
+ | expr length $1 | ||
+ | } | ||
+ | fi | ||
+ | |||
+ | |||
+ | # | ||
+ | # Prepend zeros to $1 and return a string that is $2 characters long | ||
+ | # | ||
+ | function mklen () | ||
+ | { | ||
+ | o1=$1 | ||
+ | while [ `eval strlen ${o1}` -lt ${2} ]; do | ||
+ | o1="0${o1}" | ||
+ | done | ||
+ | echo $o1 | ||
+ | } | ||
+ | |||
+ | # | ||
+ | # Get uid of $1 (or current user if $1 empty) | ||
+ | # | ||
+ | function get_uid() { | ||
+ | id $1 2>/dev/null | cut -d ' ' -f 1 | sed "s/uid=//" | cut -d '(' -f 1 | ||
+ | } | ||
+ | |||
+ | |||
+ | # | ||
+ | # Initialize autochanger's state directory if not already initialized | ||
+ | # | ||
+ | function init_statedir() { | ||
+ | debug "Initializing $statedir" | ||
+ | # Create state directory if needed | ||
+ | if [ ! -d "${statedir}" ]; then | ||
+ | if [ "$su_uid" != "" ]; then | ||
+ | su -c "mkdir ${statedir} &>/dev/null" $su_uid | ||
+ | else | ||
+ | mkdir ${statedir} &>/dev/null | ||
+ | fi | ||
+ | if [ $? -ne 0 ]; then | ||
+ | echo "Could not create ${statedir}" | ||
+ | exit 1 | ||
+ | fi | ||
+ | chmod 770 ${statedir} &>/dev/null | ||
+ | if [ $? -ne 0 ]; then | ||
+ | echo "Could not chmod ${statedir}" | ||
+ | exit 1 | ||
+ | fi | ||
+ | fi | ||
+ | # Create nextmag file to hold max magazine index used | ||
+ | if [ ! -f "${statedir}/nextmag" ]; then | ||
+ | if [ "$su_uid" != "" ]; then | ||
+ | su -c "echo 0 >${statedir}/nextmag" $su_uid | ||
+ | else | ||
+ | echo 0 >${statedir}/nextmag | ||
+ | fi | ||
+ | if [ $? -ne 0 ]; then | ||
+ | echo "Could not create ${statedir}/nextmag" | ||
+ | exit 1 | ||
+ | fi | ||
+ | chmod 660 ${statedir}/nextmag | ||
+ | if [ $? -ne 0 ]; then | ||
+ | echo "Could not chmod ${statedir}/nextmag" | ||
+ | exit 1 | ||
+ | fi | ||
+ | fi | ||
+ | # Check nextmag value | ||
+ | nextmag=`cat "${statedir}/nextmag"` | ||
+ | if [ $? -ne 0 -o "${nextmag}" == "" -o $nextmag -lt 0 -o $nextmag -gt 99 ]; then | ||
+ | echo "${statedir}/nextmag has invalid value" | ||
+ | return 1 | ||
+ | fi | ||
+ | # Create 'loaded' files for each virtual drive that hold the slot | ||
+ | # number currently loaded in that 'drive' | ||
+ | i=0 | ||
+ | while [ $i -le $maxdrive ]; do | ||
+ | if [ ! -f "${statedir}/loaded${i}" ]; then | ||
+ | if [ "$su_uid" != "" ]; then | ||
+ | su -c "echo 0 >${statedir}/loaded${i}" $su_uid | ||
+ | else | ||
+ | echo 0 >${statedir}/loaded${i} | ||
+ | fi | ||
+ | if [ $? -ne 0 ]; then | ||
+ | echo "Could not create ${statedir}/loaded${i}" | ||
+ | exit 1 | ||
+ | fi | ||
+ | if [ "$su_uid" != "" ]; then | ||
+ | su -c "chmod 660 ${statedir}/loaded${i}" $su_uid | ||
+ | else | ||
+ | chmod 660 ${statedir}/loaded${i} | ||
+ | fi | ||
+ | if [ $? -ne 0 ]; then | ||
+ | echo "Could not chmod ${statedir}/loaded${i}" | ||
+ | exit 1 | ||
+ | fi | ||
+ | fi | ||
+ | i=`expr ${i} + 1` | ||
+ | done | ||
+ | } | ||
+ | |||
+ | |||
+ | # | ||
+ | # Get magazine index of currently loaded magazine | ||
+ | # | ||
+ | function get_magazine() { | ||
+ | debug "Get magazine index" | ||
+ | # Check for mountpoint dir | ||
+ | if [ ! -d ${mountpoint} ]; then | ||
+ | echo "No magazine loaded at ${mountpoint}" | ||
+ | exit 1 | ||
+ | fi | ||
+ | # Check magazine for existing index | ||
+ | if [ ! -f "${mountpoint}/index" ]; then | ||
+ | echo "00" | ||
+ | return 1 | ||
+ | fi | ||
+ | mi=`cat "${mountpoint}/index"` | ||
+ | if [ $? -ne 0 ]; then | ||
+ | echo "Failed to read ${mountpoint}/index" | ||
+ | exit 1 | ||
+ | fi | ||
+ | # must be 1-99 | ||
+ | if [ $mi -lt 1 -o $mi -gt 99 ]; then | ||
+ | echo "Magazine has invalid index ${mi}" | ||
+ | exit 1 | ||
+ | fi | ||
+ | # make magazine index 2 digits | ||
+ | eval mklen ${mi} 2 | ||
+ | return 0 | ||
+ | } | ||
+ | |||
+ | # | ||
+ | # Initialize magazine if not already initialized | ||
+ | # | ||
+ | function init_magazine() { | ||
+ | debug "Initializing magazine" | ||
+ | # Get max magazine index that has been used | ||
+ | nextmag=`cat "${statedir}/nextmag"` | ||
+ | if [ $? -ne 0 -o "${nextmag}" == "" ]; then | ||
+ | echo "Failed to read ${statedir}/nextmag" | ||
+ | exit 1 | ||
+ | fi | ||
+ | # Check magazine for existing index | ||
+ | if [ -f "${mountpoint}/index" ]; then | ||
+ | # retrieve existing magazine index | ||
+ | mi=`cat "${mountpoint}/index"` | ||
+ | if [ $? -ne 0 ]; then | ||
+ | echo "Failed to read ${mountpoint}/index" | ||
+ | exit 1 | ||
+ | fi | ||
+ | # must be 1-99 | ||
+ | if [ $mi -lt 1 -o $mi -gt 99 ]; then | ||
+ | echo "Magazine has invalid index ${mi}" | ||
+ | exit 1 | ||
+ | fi | ||
+ | else | ||
+ | # new magazine, so assign it the next avail index | ||
+ | mi=`expr ${nextmag} + 1` | ||
+ | if [ $mi -lt 0 -o $mi -gt 99 ]; then | ||
+ | echo "Max magazines exceeded" | ||
+ | exit 1 | ||
+ | fi | ||
+ | if [ "$su_uid" != "" ]; then | ||
+ | su -c "echo ${mi} >${mountpoint}/index" $su_uid | ||
+ | else | ||
+ | echo ${mi} >${mountpoint}/index | ||
+ | fi | ||
+ | if [ $? -ne 0 ]; then | ||
+ | echo "Failed to write ${mountpoint}/index" | ||
+ | exit 1 | ||
+ | fi | ||
+ | chmod 640 ${mountpoint}/index 2>/dev/null | ||
+ | fi | ||
+ | # make sure max index used is up to date | ||
+ | if [ $mi -gt $nextmag ]; then | ||
+ | echo $mi 2>/dev/null >"${statedir}/nextmag" | ||
+ | if [ $? -ne 0 ]; then | ||
+ | echo "Failed to update ${statedir}/nextmag" | ||
+ | exit 1 | ||
+ | fi | ||
+ | fi | ||
+ | # make magazine index 2 digits | ||
+ | magindex=`eval mklen ${mi} 2` | ||
+ | # setup slot files (ie. virtual tapes) | ||
+ | i=1 | ||
+ | while [ $i -le $magslots ]; do | ||
+ | s=`eval mklen ${i} 3` | ||
+ | f="${mountpoint}/m${magindex}s${s}" | ||
+ | if [ ! -f "${f}" ]; then | ||
+ | if [ "$su_uid" != "" ]; then | ||
+ | su -c "touch ${f} &>/dev/null" $su_uid | ||
+ | else | ||
+ | touch ${f} &>/dev/null | ||
+ | fi | ||
+ | if [ $? -ne 0 ]; then | ||
+ | echo "Failed to create ${f}" | ||
+ | exit 1 | ||
+ | fi | ||
+ | fi | ||
+ | i=`expr ${i} + 1` | ||
+ | done | ||
+ | return 0 | ||
+ | } | ||
+ | |||
+ | |||
+ | # | ||
+ | # Get sd status with bconsole | ||
+ | # | ||
+ | function bconsole_sd_status() { | ||
+ | debug "Doing 'status storage' with bconsole" | ||
+ | $bconsole <<EOD_SDSTAT | ||
+ | status storage=$baculasd | ||
+ | quit | ||
+ | EOD_SDSTAT | ||
+ | } | ||
+ | |||
+ | |||
+ | # | ||
+ | # Delete volume with bconsole param1 = slot | ||
+ | # | ||
+ | function bconsole_delete_volume() { | ||
+ | debug "Doing 'delete volume' with bconsole" | ||
+ | s=`eval mklen $1 3` | ||
+ | $bconsole <<EOD_DELVOL | ||
+ | delete volume=m${magindex}s${s} | ||
+ | yes | ||
+ | quit | ||
+ | EOD_DELVOL | ||
+ | } | ||
+ | |||
+ | |||
+ | # | ||
+ | # Label volumes from barcodes with bconsole | ||
+ | # | ||
+ | function bconsole_label_barcodes() { | ||
+ | debug "Doing 'label barcodes' with bconsole" | ||
+ | $bconsole <<EOD_SDSTAT | ||
+ | label storage=$baculasd pool=$purgepool drive=0 barcodes | ||
+ | yes | ||
+ | quit | ||
+ | EOD_SDSTAT | ||
+ | } | ||
+ | |||
+ | # | ||
+ | # Checks if any of magazine's volumes are in use | ||
+ | # | ||
+ | function volumes_in_use() { | ||
+ | debug "Checking for in use volumes" | ||
+ | inuse="" | ||
+ | bconsole_sd_status | while read f; do | ||
+ | #echo $f | ||
+ | a=`echo ${f} | grep ^${magindex}` | ||
+ | if [ "$a" != "" -a "$inuse" == "" ]; then | ||
+ | inuse=`echo $f | cut -d ' ' -f 1` | ||
+ | fi | ||
+ | done | ||
+ | if [ "$inuse" != "" ]; then | ||
+ | echo $inuse | ||
+ | fi | ||
+ | } | ||
+ | |||
+ | |||
+ | # | ||
+ | # Unload all drives | ||
+ | # | ||
+ | function unload_drives() { | ||
+ | debug "Unloading all drives" | ||
+ | vuse=`eval volumes_in_use` | ||
+ | if [ "${vuse}" != "" ]; then | ||
+ | return 1 | ||
+ | fi | ||
+ | i=0 | ||
+ | while [ $i -le $maxdrive ]; do | ||
+ | unlink "${statedir}/drive${i}" 2>/dev/null >/dev/null | ||
+ | echo "0" >"${statedir}/loaded${i}" | ||
+ | i=`expr ${i} + 1` | ||
+ | done | ||
+ | return 0 | ||
+ | } | ||
+ | |||
+ | |||
+ | # | ||
+ | # check parameter count on commandline | ||
+ | # | ||
+ | function check_parm_count() { | ||
+ | pCount=$1 | ||
+ | pCountNeed=$2 | ||
+ | if test $pCount -lt $pCountNeed; then | ||
+ | echo "usage: vchanger ctl-device command [slot archive-device drive-index]" | ||
+ | echo " Insufficient number of arguments 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 | ||
+ | } | ||
+ | |||
+ | # Setup arguments | ||
+ | check_parm_count $# 2 | ||
+ | ctl=$1 | ||
+ | cmd=$2 | ||
+ | slot=$3 | ||
+ | device=$4 | ||
+ | drive=$5 | ||
+ | |||
+ | # Setup default config values | ||
+ | baculasd= | ||
+ | baculasd_user=bacula | ||
+ | bconsole="/etc/bacula/bconsole" | ||
+ | magslots=10 | ||
+ | maxdrive=0 | ||
+ | mountpoint= | ||
+ | purgepool="Scratch" | ||
+ | statedir= | ||
+ | |||
+ | # Pull in conf file | ||
+ | if [ -f $ctl ]; then | ||
+ | . $ctl | ||
+ | else | ||
+ | echo "Config file ${ctl} not found" | ||
+ | exit 1 | ||
+ | fi | ||
+ | |||
+ | # When invoked by root, create files/dirs as bacula-sd user | ||
+ | su_uid= | ||
+ | myuid=`eval get_uid` | ||
+ | if [ "$myuid" == "0" -a "$baculasd_user" != "" ]; then | ||
+ | buid=`eval get_uid $baculasd_user` | ||
+ | if [ "$buid" == "" ]; then | ||
+ | echo "bacula-sd user $baculasd_user not found" | ||
+ | exit 1 | ||
+ | fi | ||
+ | if [ "$buid" != "0" ]; then | ||
+ | su_uid=baculasd_user | ||
+ | fi | ||
+ | fi | ||
+ | |||
+ | # check for required config values | ||
+ | if [ "${mountpoint}" == "" ]; then | ||
+ | echo "Required variable 'mountpoint' not defined in ${ctl}" | ||
+ | exit 1 | ||
+ | fi | ||
+ | if [ "${baculasd}" == "" ]; then | ||
+ | echo "Required variable 'baculasd' not defined in ${ctl}" | ||
+ | exit 1 | ||
+ | fi | ||
+ | if [ "${statedir}" == "" ]; then | ||
+ | echo "Required variable 'statedir' not defined in ${ctl}" | ||
+ | exit 1 | ||
+ | fi | ||
+ | if [ "${magslots}" == "" -o $magslots -lt 1 -o $magslots -gt 999 ]; then | ||
+ | echo "Ivalid value for 'magslots' in ${ctl}" | ||
+ | exit 1 | ||
+ | fi | ||
+ | if [ "${maxdrive}" == "" -o $maxdrive -lt 0 -o $maxdrive -ge $magslots ]; then | ||
+ | echo "Invalid value for 'maxdrive' in ${ctl}" | ||
+ | exit 1 | ||
+ | fi | ||
+ | if [ "${bconsole}" == "" -o ! -f "${bconsole}" ]; then | ||
+ | echo "Ivalid value for 'bconsole' in ${ctl}" | ||
+ | exit 1 | ||
+ | fi | ||
+ | if [ "${purgepool}" == "" ]; then | ||
+ | echo "Invalid value for 'purgepool' in ${ctl}" | ||
+ | exit 1 | ||
+ | fi | ||
+ | |||
+ | # attempt to set defaults for params not specified on command line | ||
+ | if [ "${drive}" == "" ]; then | ||
+ | drive=0 | ||
+ | fi | ||
+ | if [ "${device}" == "" ]; then | ||
+ | device="${statedir}/drive${drive}" | ||
+ | fi | ||
+ | |||
+ | # make sure archive device makes sense | ||
+ | if [ "${device}" != "${statedir}/drive${drive}" ]; then | ||
+ | echo "Param 4 (archive device) must be ${statedir}/driveN," | ||
+ | echo " where N is the drive number passed as param 5" | ||
+ | exit 1 | ||
+ | fi | ||
+ | |||
+ | # Initialize state directory for this autochanger | ||
+ | init_statedir | ||
+ | |||
+ | debug "Parms: $ctl $cmd $slot $device $drive" | ||
+ | |||
+ | # | ||
+ | # Process command | ||
+ | # | ||
+ | case $cmd in | ||
+ | list) | ||
+ | check_parm_count $# 2 | ||
+ | debug "Doing list command" | ||
+ | init_magazine | ||
+ | if [ $? -ne 0 ]; then | ||
+ | echo "Magazine Not Loaded" | ||
+ | exit 1 | ||
+ | fi | ||
+ | i=1 | ||
+ | while [ $i -le $magslots ]; do | ||
+ | s=`eval mklen ${i} 3` | ||
+ | echo "${i}:m${magindex}s${s}" | ||
+ | i=`expr ${i} + 1` | ||
+ | done | ||
+ | ;; | ||
+ | slots) | ||
+ | check_parm_count $# 2 | ||
+ | debug "Doing slots command" | ||
+ | echo $magslots | ||
+ | ;; | ||
+ | load) | ||
+ | check_parm_count $# 5 | ||
+ | debug "Doing load slot $slot into drive $drive" | ||
+ | if [ $drive -gt $maxdrive ]; then | ||
+ | echo "Drive ($drive) out of range (0-${maxdrive})" | ||
+ | exit 1 | ||
+ | fi | ||
+ | if [ $slot -gt $magslots ]; then | ||
+ | echo "Slot ($slot) out of range (1-$magslots)" | ||
+ | exit 1 | ||
+ | fi | ||
+ | ld=`cat "${statedir}/loaded${drive}"` | ||
+ | if [ $? -ne 0 ]; then | ||
+ | echo "Failed to read ${statedir}/loaded${drive}" | ||
+ | exit 1 | ||
+ | fi | ||
+ | if [ $ld -eq 0 ]; then | ||
+ | unlink "${device}" &>/dev/null | ||
+ | # make sure slot is not loaded in another drive | ||
+ | i=0 | ||
+ | while [ $i -le $maxdrive ]; do | ||
+ | if [ $i -ne $drive ]; then | ||
+ | ldi=`cat "${statedir}/loaded${i}"` | ||
+ | if [ $ldi -eq $slot ]; then | ||
+ | echo "Storage Element ${slot} Empty (loaded in drive ${i})" | ||
+ | exit 1 | ||
+ | fi | ||
+ | fi | ||
+ | i=`expr ${i} + 1` | ||
+ | done | ||
+ | init_magazine | ||
+ | if [ $? -ne 0 ]; then | ||
+ | echo "Magazine Not Loaded" | ||
+ | exit 1 | ||
+ | fi | ||
+ | s=`eval mklen ${slot} 3` | ||
+ | if [ "$su_uid" != "" ]; then | ||
+ | su -c "ln -s '${mountpoint}/m${magindex}s${s}' '${device}'" $su_uid | ||
+ | else | ||
+ | ln -s "${mountpoint}/m${magindex}s${s}" "${device}" | ||
+ | fi | ||
+ | echo $slot >"${statedir}/loaded${drive}" | ||
+ | else | ||
+ | echo "Drive ${drive} Full (Storage element ${ld} loaded)" | ||
+ | exit 1 | ||
+ | fi | ||
+ | ;; | ||
+ | unload) | ||
+ | check_parm_count $# 5 | ||
+ | debug "Doing unload drive $drive into slot $slot" | ||
+ | if [ $drive -gt $maxdrive ]; then | ||
+ | echo "Drive ($drive) out of range (0-${maxdrive})" | ||
+ | exit 1 | ||
+ | fi | ||
+ | if [ $slot -gt $magslots ]; then | ||
+ | echo "Slot ($slot) out of range (1-$magslots)" | ||
+ | exit 1 | ||
+ | fi | ||
+ | ld=`cat "${statedir}/loaded${drive}"` | ||
+ | if [ $? -ne 0 ]; then | ||
+ | echo "Failed to read ${statedir}/loaded${drive}" | ||
+ | exit 1 | ||
+ | fi | ||
+ | if [ $slot -eq $ld ]; then | ||
+ | echo "0" >"${statedir}/loaded${drive}" | ||
+ | if [ $? -ne 0 ]; then | ||
+ | echo "Failed to write ${statedir}/loaded${drive}" | ||
+ | exit 1 | ||
+ | fi | ||
+ | unlink "${device}" 2>/dev/null >/dev/null | ||
+ | exit 0 | ||
+ | fi | ||
+ | if [ $ld -eq 0 ]; then | ||
+ | echo "Drive ${drive} Is Empty" | ||
+ | exit 1 | ||
+ | else | ||
+ | echo "Storage Element ${slot} is Already Full" | ||
+ | exit 1 | ||
+ | fi | ||
+ | ;; | ||
+ | loaded) | ||
+ | check_parm_count $# 5 | ||
+ | debug "Doing loaded command for drive $drive" | ||
+ | if [ $drive -gt $maxdrive ]; then | ||
+ | echo "Drive ($drive) out of range (0-${maxdrive})" | ||
+ | exit 1 | ||
+ | fi | ||
+ | if [ $slot -gt $magslots ]; then | ||
+ | echo "Slot ($slot) out of range (1-$magslots)" | ||
+ | exit 1 | ||
+ | fi | ||
+ | cat "${statedir}/loaded${drive}" | ||
+ | ;; | ||
+ | purge) | ||
+ | check_parm_count $# 2 | ||
+ | debug "Doing purge command" | ||
+ | magindex=`eval get_magazine` | ||
+ | if [ "$magazine" == "00" ]; then | ||
+ | echo No magazine loaded | ||
+ | fi | ||
+ | cm="" | ||
+ | while [ "$cm" != "y" -a "$cm" != "n" ]; do | ||
+ | echo -n "Purge all volumes on magazine $magindex (y/n)? " | ||
+ | read cm | ||
+ | if [ "$cm" == "Y" ]; then | ||
+ | cm="y" | ||
+ | fi | ||
+ | if [ "$cm" == "N" ]; then | ||
+ | cm="n" | ||
+ | fi | ||
+ | done | ||
+ | if [ "$cm" == "n" ]; then | ||
+ | exit 0 | ||
+ | fi | ||
+ | echo "Unloading $baculasd drives" | ||
+ | unload_drives | ||
+ | if [ $? -ne 0 ]; then | ||
+ | echo Volume `eval volumes_in_use` in use...aborting | ||
+ | exit 1 | ||
+ | fi | ||
+ | echo "Deleting magazine $magindex volumes" | ||
+ | i=1 | ||
+ | while [ $i -le $magslots ]; do | ||
+ | bconsole_delete_volume $i &>/tmp/vclog | ||
+ | rm -f "${mountpoint}/m${magindex}s${s}" | ||
+ | echo "deleted volume m${magindex}s${s}" | ||
+ | i=`expr ${i} + 1` | ||
+ | done | ||
+ | echo "Doing 'label barcodes' to re-create magazine's volumes" | ||
+ | bconsole_label_barcodes | while read f; do | ||
+ | echo $f | ||
+ | done | ||
+ | ;; | ||
+ | *) | ||
+ | echo "Command not recognized" | ||
+ | exit 1 | ||
+ | ;; | ||
+ | esac | ||
+ | |||
+ | exit 0 | ||
+ | # eof | ||
+ | </pre> |
Revision as of 11:00, 3 March 2014
CentOS 6.5 Install
yum install mysql-server mysql-devel
service mysqld start chkconfig mysqld on mysqladmin -u root password Y0uR3l173P455w0rd
yum install bareos-database-mysql yum install bareos
/usr/lib/bareos/scripts/create_bareos_database -u root -p /usr/lib/bareos/scripts/make_bareos_tables -u root -p /usr/lib/bareos/scripts/grant_bareos_privileges -u root -p
service bareos-dir start service bareos-sd start service bareos-fd start
Links
- http://www.unixmen.com/install-and-configure-bacula-server-in-centos-6-4-rhel-6-4/
- http://www.bareos.org/en/documentation.html
- http://doc.bareos.org/master/html/bareos-manual-main-reference.html
Archlinux GUI Admin
yaourt bareos-bat
Configure On CentOS 6.5
nano /etc/bareos/vchanger
</pre>
- !/bin/sh
- Bacula interface to virtual autochanger using removable disk drives
- Based (somewhat) on the "disk-changer" script from bacula 1.39.26
- Vchanger is a Bacula autochanger script that emulates a conventional
- magazine-based tape library device using removable disk drives.
- Partitions on the removable drives are used as virtual magazines,
- where each "magazine" contains the same number of virtual slots. Each
- "slot" holds one virtual tape, where a "tape" is a regular file that
- Bacula treats as a "Device Type = File" volume.
- This script will be invoked by Bacula using the Bacula Autochanger
- Interface and will be passed the following arguments:
- vchanger "changer-device" "command" "slot" "archive-device" "drive-index"
- $1 $2 $3 #4 #5
- See the Bacula documentation and the Bacula Removable Disk Howto for
- further details.
- Copyright (C) 2006 Josh Fisher
- Permission to use, copy, modify, distribute, and sell this software
- and its documentation for any purpose is hereby granted without fee,
- provided that the above copyright notice appear in all copies. This
- software is provided "as is" without express or implied warranty.
- This software is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- $Id: vchanger,v 0.7.4 2006/12/01 09:29:04 jfisher Exp $
- log whats done
- to turn on logging, uncomment the following line
- touch $wd/vchanger.log
- Write to a log file
- To log debugging info, create file /var/bacula/vchanger.log
- with write permission for bacula-sd user. To stop logging,
- delete file /var/bacula/vchanger.log
dbgfile="/var/bacula/vchanger.log" function debug() {
if test -e $dbgfile; then
echo "`date +\"%Y%m%d-%H:%M:%S\"` $*" >> $dbgfile
fi
}
- Return length of string $1
if [ `uname` = "FreeBSD" ] then
function strlen () { expr -- "$1" : ".*" }
else
function strlen () { expr length $1 }
fi
- Prepend zeros to $1 and return a string that is $2 characters long
function mklen () {
o1=$1 while [ `eval strlen ${o1}` -lt ${2} ]; do o1="0${o1}" done echo $o1
}
- Get uid of $1 (or current user if $1 empty)
function get_uid() {
id $1 2>/dev/null | cut -d ' ' -f 1 | sed "s/uid=//" | cut -d '(' -f 1
}
- Initialize autochanger's state directory if not already initialized
function init_statedir() {
debug "Initializing $statedir" # Create state directory if needed if [ ! -d "${statedir}" ]; then if [ "$su_uid" != "" ]; then su -c "mkdir ${statedir} &>/dev/null" $su_uid else mkdir ${statedir} &>/dev/null fi if [ $? -ne 0 ]; then echo "Could not create ${statedir}" exit 1 fi chmod 770 ${statedir} &>/dev/null if [ $? -ne 0 ]; then echo "Could not chmod ${statedir}" exit 1 fi fi # Create nextmag file to hold max magazine index used if [ ! -f "${statedir}/nextmag" ]; then if [ "$su_uid" != "" ]; then su -c "echo 0 >${statedir}/nextmag" $su_uid else
echo 0 >${statedir}/nextmag
fi if [ $? -ne 0 ]; then echo "Could not create ${statedir}/nextmag" exit 1 fi chmod 660 ${statedir}/nextmag if [ $? -ne 0 ]; then echo "Could not chmod ${statedir}/nextmag" exit 1 fi fi # Check nextmag value nextmag=`cat "${statedir}/nextmag"` if [ $? -ne 0 -o "${nextmag}" == "" -o $nextmag -lt 0 -o $nextmag -gt 99 ]; then echo "${statedir}/nextmag has invalid value" return 1 fi # Create 'loaded' files for each virtual drive that hold the slot # number currently loaded in that 'drive' i=0 while [ $i -le $maxdrive ]; do if [ ! -f "${statedir}/loaded${i}" ]; then if [ "$su_uid" != "" ]; then su -c "echo 0 >${statedir}/loaded${i}" $su_uid else echo 0 >${statedir}/loaded${i} fi if [ $? -ne 0 ]; then echo "Could not create ${statedir}/loaded${i}" exit 1 fi if [ "$su_uid" != "" ]; then su -c "chmod 660 ${statedir}/loaded${i}" $su_uid else chmod 660 ${statedir}/loaded${i} fi if [ $? -ne 0 ]; then echo "Could not chmod ${statedir}/loaded${i}" exit 1 fi fi i=`expr ${i} + 1` done
}
- Get magazine index of currently loaded magazine
function get_magazine() {
debug "Get magazine index" # Check for mountpoint dir if [ ! -d ${mountpoint} ]; then echo "No magazine loaded at ${mountpoint}" exit 1 fi # Check magazine for existing index if [ ! -f "${mountpoint}/index" ]; then echo "00" return 1 fi mi=`cat "${mountpoint}/index"` if [ $? -ne 0 ]; then echo "Failed to read ${mountpoint}/index" exit 1 fi # must be 1-99 if [ $mi -lt 1 -o $mi -gt 99 ]; then echo "Magazine has invalid index ${mi}" exit 1 fi # make magazine index 2 digits eval mklen ${mi} 2 return 0
}
- Initialize magazine if not already initialized
function init_magazine() {
debug "Initializing magazine" # Get max magazine index that has been used nextmag=`cat "${statedir}/nextmag"` if [ $? -ne 0 -o "${nextmag}" == "" ]; then echo "Failed to read ${statedir}/nextmag" exit 1 fi # Check magazine for existing index if [ -f "${mountpoint}/index" ]; then # retrieve existing magazine index mi=`cat "${mountpoint}/index"` if [ $? -ne 0 ]; then echo "Failed to read ${mountpoint}/index" exit 1 fi # must be 1-99 if [ $mi -lt 1 -o $mi -gt 99 ]; then echo "Magazine has invalid index ${mi}" exit 1 fi else # new magazine, so assign it the next avail index mi=`expr ${nextmag} + 1` if [ $mi -lt 0 -o $mi -gt 99 ]; then echo "Max magazines exceeded" exit 1 fi if [ "$su_uid" != "" ]; then su -c "echo ${mi} >${mountpoint}/index" $su_uid else echo ${mi} >${mountpoint}/index fi if [ $? -ne 0 ]; then echo "Failed to write ${mountpoint}/index" exit 1 fi chmod 640 ${mountpoint}/index 2>/dev/null fi # make sure max index used is up to date if [ $mi -gt $nextmag ]; then echo $mi 2>/dev/null >"${statedir}/nextmag" if [ $? -ne 0 ]; then echo "Failed to update ${statedir}/nextmag" exit 1 fi fi # make magazine index 2 digits magindex=`eval mklen ${mi} 2` # setup slot files (ie. virtual tapes) i=1 while [ $i -le $magslots ]; do s=`eval mklen ${i} 3` f="${mountpoint}/m${magindex}s${s}" if [ ! -f "${f}" ]; then if [ "$su_uid" != "" ]; then su -c "touch ${f} &>/dev/null" $su_uid else touch ${f} &>/dev/null fi if [ $? -ne 0 ]; then echo "Failed to create ${f}" exit 1 fi fi i=`expr ${i} + 1` done return 0
}
- Get sd status with bconsole
function bconsole_sd_status() {
debug "Doing 'status storage' with bconsole" $bconsole <<EOD_SDSTAT
status storage=$baculasd quit EOD_SDSTAT }
- Delete volume with bconsole param1 = slot
function bconsole_delete_volume() {
debug "Doing 'delete volume' with bconsole" s=`eval mklen $1 3` $bconsole <<EOD_DELVOL
delete volume=m${magindex}s${s} yes quit EOD_DELVOL }
- Label volumes from barcodes with bconsole
function bconsole_label_barcodes() {
debug "Doing 'label barcodes' with bconsole" $bconsole <<EOD_SDSTAT
label storage=$baculasd pool=$purgepool drive=0 barcodes yes quit EOD_SDSTAT }
- Checks if any of magazine's volumes are in use
function volumes_in_use() {
debug "Checking for in use volumes" inuse="" bconsole_sd_status | while read f; do #echo $f a=`echo ${f} | grep ^${magindex}` if [ "$a" != "" -a "$inuse" == "" ]; then inuse=`echo $f | cut -d ' ' -f 1` fi done if [ "$inuse" != "" ]; then echo $inuse fi
}
- Unload all drives
function unload_drives() {
debug "Unloading all drives" vuse=`eval volumes_in_use` if [ "${vuse}" != "" ]; then return 1 fi i=0 while [ $i -le $maxdrive ]; do unlink "${statedir}/drive${i}" 2>/dev/null >/dev/null echo "0" >"${statedir}/loaded${i}" i=`expr ${i} + 1` done return 0
}
- check parameter count on commandline
function check_parm_count() {
pCount=$1 pCountNeed=$2 if test $pCount -lt $pCountNeed; then
echo "usage: vchanger ctl-device command [slot archive-device drive-index]" echo " Insufficient number of arguments 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
}
- Setup arguments
check_parm_count $# 2 ctl=$1 cmd=$2 slot=$3 device=$4 drive=$5
- Setup default config values
baculasd= baculasd_user=bacula bconsole="/etc/bacula/bconsole" magslots=10 maxdrive=0 mountpoint= purgepool="Scratch" statedir=
- Pull in conf file
if [ -f $ctl ]; then
. $ctl
else
echo "Config file ${ctl} not found" exit 1
fi
- When invoked by root, create files/dirs as bacula-sd user
su_uid= myuid=`eval get_uid` if [ "$myuid" == "0" -a "$baculasd_user" != "" ]; then
buid=`eval get_uid $baculasd_user` if [ "$buid" == "" ]; then echo "bacula-sd user $baculasd_user not found" exit 1 fi if [ "$buid" != "0" ]; then su_uid=baculasd_user fi
fi
- check for required config values
if [ "${mountpoint}" == "" ]; then
echo "Required variable 'mountpoint' not defined in ${ctl}" exit 1
fi if [ "${baculasd}" == "" ]; then
echo "Required variable 'baculasd' not defined in ${ctl}" exit 1
fi if [ "${statedir}" == "" ]; then
echo "Required variable 'statedir' not defined in ${ctl}" exit 1
fi if [ "${magslots}" == "" -o $magslots -lt 1 -o $magslots -gt 999 ]; then
echo "Ivalid value for 'magslots' in ${ctl}" exit 1
fi if [ "${maxdrive}" == "" -o $maxdrive -lt 0 -o $maxdrive -ge $magslots ]; then
echo "Invalid value for 'maxdrive' in ${ctl}" exit 1
fi if [ "${bconsole}" == "" -o ! -f "${bconsole}" ]; then
echo "Ivalid value for 'bconsole' in ${ctl}" exit 1
fi if [ "${purgepool}" == "" ]; then
echo "Invalid value for 'purgepool' in ${ctl}" exit 1
fi
- attempt to set defaults for params not specified on command line
if [ "${drive}" == "" ]; then
drive=0
fi if [ "${device}" == "" ]; then
device="${statedir}/drive${drive}"
fi
- make sure archive device makes sense
if [ "${device}" != "${statedir}/drive${drive}" ]; then
echo "Param 4 (archive device) must be ${statedir}/driveN," echo " where N is the drive number passed as param 5" exit 1
fi
- Initialize state directory for this autochanger
init_statedir
debug "Parms: $ctl $cmd $slot $device $drive"
- Process command
case $cmd in
list) check_parm_count $# 2 debug "Doing list command" init_magazine if [ $? -ne 0 ]; then echo "Magazine Not Loaded" exit 1 fi i=1 while [ $i -le $magslots ]; do s=`eval mklen ${i} 3` echo "${i}:m${magindex}s${s}" i=`expr ${i} + 1` done ;; slots) check_parm_count $# 2 debug "Doing slots command" echo $magslots ;; load) check_parm_count $# 5 debug "Doing load slot $slot into drive $drive" if [ $drive -gt $maxdrive ]; then echo "Drive ($drive) out of range (0-${maxdrive})" exit 1 fi if [ $slot -gt $magslots ]; then echo "Slot ($slot) out of range (1-$magslots)" exit 1 fi ld=`cat "${statedir}/loaded${drive}"` if [ $? -ne 0 ]; then echo "Failed to read ${statedir}/loaded${drive}" exit 1 fi if [ $ld -eq 0 ]; then unlink "${device}" &>/dev/null # make sure slot is not loaded in another drive i=0 while [ $i -le $maxdrive ]; do if [ $i -ne $drive ]; then ldi=`cat "${statedir}/loaded${i}"` if [ $ldi -eq $slot ]; then echo "Storage Element ${slot} Empty (loaded in drive ${i})" exit 1 fi fi i=`expr ${i} + 1` done init_magazine if [ $? -ne 0 ]; then echo "Magazine Not Loaded" exit 1 fi s=`eval mklen ${slot} 3` if [ "$su_uid" != "" ]; then su -c "ln -s '${mountpoint}/m${magindex}s${s}' '${device}'" $su_uid else ln -s "${mountpoint}/m${magindex}s${s}" "${device}" fi echo $slot >"${statedir}/loaded${drive}" else echo "Drive ${drive} Full (Storage element ${ld} loaded)" exit 1 fi ;; unload) check_parm_count $# 5 debug "Doing unload drive $drive into slot $slot" if [ $drive -gt $maxdrive ]; then echo "Drive ($drive) out of range (0-${maxdrive})" exit 1 fi if [ $slot -gt $magslots ]; then echo "Slot ($slot) out of range (1-$magslots)" exit 1 fi ld=`cat "${statedir}/loaded${drive}"` if [ $? -ne 0 ]; then echo "Failed to read ${statedir}/loaded${drive}" exit 1 fi if [ $slot -eq $ld ]; then echo "0" >"${statedir}/loaded${drive}" if [ $? -ne 0 ]; then echo "Failed to write ${statedir}/loaded${drive}" exit 1 fi unlink "${device}" 2>/dev/null >/dev/null exit 0 fi if [ $ld -eq 0 ]; then echo "Drive ${drive} Is Empty" exit 1 else echo "Storage Element ${slot} is Already Full" exit 1 fi ;; loaded) check_parm_count $# 5 debug "Doing loaded command for drive $drive" if [ $drive -gt $maxdrive ]; then echo "Drive ($drive) out of range (0-${maxdrive})" exit 1 fi if [ $slot -gt $magslots ]; then echo "Slot ($slot) out of range (1-$magslots)" exit 1 fi cat "${statedir}/loaded${drive}" ;; purge) check_parm_count $# 2 debug "Doing purge command" magindex=`eval get_magazine` if [ "$magazine" == "00" ]; then echo No magazine loaded fi cm="" while [ "$cm" != "y" -a "$cm" != "n" ]; do echo -n "Purge all volumes on magazine $magindex (y/n)? " read cm if [ "$cm" == "Y" ]; then cm="y" fi if [ "$cm" == "N" ]; then cm="n" fi done if [ "$cm" == "n" ]; then exit 0 fi echo "Unloading $baculasd drives" unload_drives if [ $? -ne 0 ]; then echo Volume `eval volumes_in_use` in use...aborting exit 1 fi echo "Deleting magazine $magindex volumes" i=1 while [ $i -le $magslots ]; do bconsole_delete_volume $i &>/tmp/vclog rm -f "${mountpoint}/m${magindex}s${s}" echo "deleted volume m${magindex}s${s}" i=`expr ${i} + 1` done echo "Doing 'label barcodes' to re-create magazine's volumes" bconsole_label_barcodes | while read f; do echo $f done ;; *) echo "Command not recognized" exit 1 ;;
esac
exit 0
- eof
</pre>