Bacula-users

[Bacula-users] OpenBSD, slot-agnostic mtx-changer

2009-04-21 10:39:56
Subject: [Bacula-users] OpenBSD, slot-agnostic mtx-changer
From: "(private) HKS" <hks.private AT gmail DOT com>
To: "bacula-users AT lists.sourceforge DOT net" <Bacula-users AT lists.sourceforge DOT net>
Date: Tue, 21 Apr 2009 10:35:33 -0400
As alluded to in previous messages, I've rewritten much of mtx-changer
for my own needs. The goal was to make Bacula (2.2.8) interact nicely
with my autochanger (16 slot Dell Powervault 124T) and OS (OpenBSD
4.4). It would be able to load tapes with no regard for actual slot
numbers. All Bacula had to know was the barcode.

In other words, I have barcodes so I don't have to think about slots
and such. I wanted Bacula to act accordingly. There were also quite a
few problems between the existing mtx-changer and OpenBSD's chio
command (didn't like output formatting, chio doesn't keep track of the
tape's original slot, etc).

For reference, here's the output of "chio status -v":
---
picker 0:  voltag: <:0>
slot 0: <ACCESS,FULL> voltag: <000018L3:0>
slot 1: <ACCESS,FULL> voltag: <000020L3:0>
slot 2: <ACCESS,FULL> voltag: <000017L3:0>
slot 3: <ACCESS,FULL> voltag: <000016L3:0>
slot 4: <ACCESS> voltag: <:0>
slot 5: <ACCESS> voltag: <:0>
slot 6: <ACCESS> voltag: <:0>
slot 7: <ACCESS> voltag: <:0>
slot 8: <ACCESS> voltag: <:0>
slot 9: <ACCESS> voltag: <:0>
slot 10: <ACCESS> voltag: <:0>
slot 11: <ACCESS> voltag: <:0>
slot 12: <ACCESS> voltag: <:0>
slot 13: <ACCESS> voltag: <:0>
slot 14: <ACCESS> voltag: <:0>
slot 15: <ACCESS> voltag: <:0>
drive 0: <ACCESS,FULL> voltag: <000019L3:0>
---

You can see most of how I did this from the mtx-changer output:
---
# ./mtx-changer /dev/ch0 list
18:000018L3
20:000020L3
17:000017L3
16:000016L3
19:000019L3
# ./mtx-changer /dev/ch0 slots
20
# ./mtx-changer /dev/ch0 loaded 0 /dev/rst0 0
000019L3
# ./mtx-changer /dev/ch0 unload 0 /dev/rst0 0
# ./mtx-changer /dev/ch0 load 16 /dev/rst0 0
# ./mtx-changer /dev/ch0 loaded 0 /dev/rst0 0
000016L3
#


---

In a nutshell, this script treats slots as if they're just the most
relevant part of the barcode. If you tell it to load up slot 19, it
figures you mean barcode 000019L3 and obeys. The number of slots
reported to Bacula is always equivalent to the highest barcode in the
autochanger (to avoid out-of-bounds problems). When told to unload the
loaded tape, the script ignores the slot argument and just dumps the
tape into the first empty slot it finds.

Backups work nicely with this, though the autochanger test requires a
bit of mucking about with the script to succeed (see commented section
in "load" command). Keep in mind I've only used this on my very
specific system, so your mileage will vary.

-HKS



#!/bin/sh
#
# Bacula interface to chio autoloader
#
#  $Id: mtx-changer.in 5360 2007-08-16 13:01:19Z pbuschman $
#
#  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?
#
#  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 chio load.
#
#  N.B. If you change the script, take care to return either
#   the chio exit code or a 0. If the script exits with a non-zero
#   exit code, Bacula will assume the request failed.
#
#
# Modified 2009-03-06 to accomodate OpenBSD 4.4 and, specifically,
chio with a Powervault 124T
#
# The main purpose of these changes was to make the script
slot-agnostic - we don't care what slot
# a tape is in - that's why we have them labeled.
#
# Change notes by command:
# unload        - ignores the slot number you pass it and unloads the
tape into the first empty slot it finds
# load          - treats the slot like it's a (possibly bastardized)
barcode label and attempts to load the
#                 tape with that label into the specified drive
# loaded        - returns the barcode label of the loaded tape
# list          - lists the barcode labels of all tapes in the
changer. This isn't near as cool as the original
#                 list, which printed "slot:volumetag" because this
just prints "volumetag:volumetag", but since
#                 everything else operates by volumetag, it doesn't
really matter
# slots         - report a number equal to the highest numbered tape
in the magazine
#

MTX=/bin/chio

# mt status output
# SunOS     No Additional Sense
# FreeBSD   Current Driver State: at rest.
# Linux     ONLINE

OS=`uname`
case ${OS} in
  SunOS)
    ready="No Additional Sense"
    ;;
  FreeBSD)
    ready="Current Driver State: at rest."
    ;;
  OpenBSD)
    ready="Mounted|No medium found"
    ;;
  *)
    ready="ONLINE"
  ;;
esac

#
# log whats done
#
# to turn on logging, uncomment the following line
touch /var/bacula/mtx.log
#
dbgfile="/var/bacula/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/mtx.XXXXXXXXXX`
  if test x${TMPFILE} = x; then
     TMPFILE="/var/bacula/mtx.$$"
     if test -f ${TMPFILE}; then
        echo "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 -E "${ready}" > /dev/null; 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 "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)
        check_parm_count $# 2
        ;;
    slots)
        check_parm_count $# 2
        ;;
    *)
        check_parm_count $# 5
        ;;
esac


# Setup arguments
ctl=$1
cmd="$2"
voltag=$3
device=$4
drive=$5

debug "Parms: $ctl $cmd $voltag $device $drive"

# find the first empty slot in the autochanger
#
first_empty_slot() {
      debug "Doing chio -f $ctl status -- to find empty slots"

# Don't think this is necessary - and it causes issues if the drive is
offline but has a tape in it
#      wait_for_drive $device

      make_temp_file
      ${MTX} -f $ctl status -v >${TMPFILE}
      rtn=$?
      # find the first empty slot
      EMPTY_SLOT=`cat ${TMPFILE} | grep " *slot [0-9]*: <ACCESS>
voltag: <:0>" | awk '{print $2}' | sed "s/:$//" | head -n 1`

      rm -f ${TMPFILE} >/dev/null 2>&1
      if [ -z $EMPTY_SLOT ]; then
        echo "No empty slot found, aborting"
        exit 1
      fi
}

# reformat voltag so it looks like a real voltag
#
format_voltag() {
      debug "Making voltag $voltag look like a real voltag"

      # we're expecting it in one of the following formats:
      # \d (1, 2, 3, etc)
      # \d\d (12, 13, etc)
      # 0000\d\dL3 (000011L3, 000002L3, etc -- this is the format we
want it in. The L3 doesn't change, so that's hardcoded)
      tmpvar=`echo -n $voltag | perl -p -e "s/^0*([1-9]?\d)$/\1L3/"`

      voltag=`printf "%08s" $tmpvar`
}

case $cmd in
   unload)
     first_empty_slot
     debug "Doing mt -f $device offline to take the device offline"
     mt -f $device offline >/dev/null 2>&1
     debug "Done with mt -f, sleeping 10 seconds"
     sleep 10
     debug "Doing chio -f $ctl move drive $drive slot $EMPTY_SLOT"
     ${MTX} -f $ctl move drive $drive slot $EMPTY_SLOT
     ;;

   load)
      format_voltag

#       # TEMPORARILY CHANGING THIS AROUND TO MAKE BTAPE WORK!
#       voltag=`echo -n $voltag | perl -p -e "s/^000001L3$/000013L3/"`
#       voltag=`echo -n $voltag | perl -p -e "s/^000002L3$/000012L3/"`

      debug "Doing chio -f $ctl move voltag $voltag drive $drive"
      ${MTX} -f $ctl move voltag $voltag drive $drive
      rtn=$?
      wait_for_drive $device
      exit $rtn
      ;;

   list)
      # coming from this output:
        # $ chio status -v
        # picker 0:  voltag: <:0>
        # slot 0: <ACCESS> voltag: <:0>
        # slot 1: <ACCESS,FULL> voltag: <000014L3:0>
        # slot 2: <ACCESS> voltag: <:0>
        # slot 3: <ACCESS> voltag: <:0>
        # slot 4: <ACCESS,FULL> voltag: <000013L3:0>
        # slot 5: <ACCESS,FULL> voltag: <000012L3:0>
        # slot 6: <ACCESS> voltag: <:0>
        # slot 7: <ACCESS,FULL> voltag: <000011L3:0>
        # slot 8: <ACCESS> voltag: <:0>
        # slot 9: <ACCESS> voltag: <:0>
        # slot 10: <ACCESS> voltag: <:0>
        # slot 11: <ACCESS> voltag: <:0>
        # slot 12: <ACCESS> voltag: <:0>
        # slot 13: <ACCESS> voltag: <:0>
        # slot 14: <ACCESS> voltag: <:0>
        # slot 15: <ACCESS> voltag: <:0>
        # drive 0: <ACCESS,FULL> voltag: <000015L3:0>
     # we want:
     # <slotnum>:<voltag>
     #
     # Since we're making this slot-agnostic, the slot output will look like:
     # <voltag-as-slotnum>:<voltag>

      debug "Doing chio -f $ctl status -- to list volumes"
      make_temp_file

      ${MTX} -f $ctl status -v >${TMPFILE}
      rtn=$?
      cat ${TMPFILE} | grep -E " *(slot|drive) [0-9]*:
<ACCESS,.*FULL.*>" | awk '{printf "%s:%s\n", $5, $5}' | sed
"s/<\([0-9]*L3\):0>/\1/g" | sed "s/^0*\([1-9]*[0-9]\)L3:/\1:/"
      rm -f ${TMPFILE} >/dev/null 2>&1
      exit $rtn
      ;;

   loaded)
      debug "Doing chio -f $ctl status -- to find what is loaded"
      make_temp_file
      ${MTX} -f $ctl status -v >${TMPFILE}
      rtn=$?

      cat ${TMPFILE} | grep " *drive $drive: <.*FULL.*>" | awk '{print
$5}' | sed "s/<\([0-9]*L3\):0>/\1/g"
      cat ${TMPFILE} | grep " *drive $drive: <.*FULL.*>" > /dev/null 2>&1
      if [ $? != 0 ]; then echo 0; fi
      rm -f ${TMPFILE} >/dev/null 2>&1
      exit $rtn
      ;;

   slots)
      # since bacula compares tape slot numbers to the number of slots
reported by mtx-changer, it will
      # reject barcodes that are higher numbered than 16 in the 124T.
So we change the slots command to
      # simply report the highest barcode number as the number of slots.
      debug "Doing chio -f $ctl status -- to get count of slots"
      ${MTX} -f $ctl status -v | grep -E '^slot.*<ACCESS,FULL>' | awk
'{print $5}' | sed -e 's/<0*//' -e 's/L3:0>//' | sort -nr | head -n 1
      ;;
esac

------------------------------------------------------------------------------
Stay on top of everything new and different, both inside and 
around Java (TM) technology - register by April 22, and save
$200 on the JavaOne (SM) conference, June 2-5, 2009, San Francisco.
300 plus technical and hands-on sessions. Register today. 
Use priority code J9JMT32. http://p.sf.net/sfu/p
_______________________________________________
Bacula-users mailing list
Bacula-users AT lists.sourceforge DOT net
https://lists.sourceforge.net/lists/listinfo/bacula-users

<Prev in Thread] Current Thread [Next in Thread>