I've interspersed some comments. I've also appended a python script
that I use for taking shanpshots of _mounted_ logical volumes, and
mounting the snapshot. The same script is used for unmounting and
releasing the snapshot.
This is not a solution for your problem because your LV is not a
file-system, but contains partitions with file-systems. Nevertheless,
you may be able to use it as a starting point and make appropriate
modifications for your case.
Hope this helps - Kel Raywood
On Sun, 18 Sep 2011, Tobias Schenk wrote:
> I try use bacula 5.0.3 on suse linux to backup lvm snapshots.
> Basically, I create a lvm snapshot called /dev/vmguests/backup using the
> RunScript directive. Unfortunately, this is a sym link to /dev/dm-6. I
> cannot be sure it is always dm-6. I would like to follow the sym link
> and backup /dev/dm-6 as raw device.
There is a command "readlink" which you can use to find the target of a
symbolic link.
e.g. tgt=$( readlink --canonicalize /dev/vmguests/backup )
> The hints I found while googling are are not working (like appending /.
> to the File directive) or obscure (like using bash scripting to resolve
> File names).
Hmm ... I then I guess you would classify using readlink in a script as
obscure.
> I cannot simply mount /dev/dm-6 to somewhere because the contents is a
> partitioned raw device of a kvm instance.
Then you need to use kpartx to create device maps from the partition
tables. These devices would contain the file-systems which you could
mount.
> Maybe it is possible resolve the link using a bash script in the file
> directive but I have not found information about when the File directive
> will be evaluated relative to RunScript.
A RunScript with "RunsWhen = Before" will do exactly that. ie. nothing
else will be evaluated until after the script has returned.
> Has anyone a working solution for lvm snapshots?
As mentioned at the top, I have a client-side script for backing up
mounted LVs. ie. You don't pass it the LV name, you pass it the
mount-point (e.g. /home) and where you want to mount the snapshot (e.g.
/.snap/home) . In the FileSet I use "strip path = 1"
My job resources contain:
RunScript {
Runs When = Before
Runs On Client = yes
Abort Job On Error = yes
Command = "/etc/bacula/scripts/snapshot -L 4G /home /.snap/home"
}
RunScript {
Runs When = After
Runs On Client = yes
Runs On Failure = yes
Command = "/etc/bacula/scripts/snapshot -d /.snap/home"
}
Client-seide python-script "/etc/bacula/scripts/snapshot":
#!/bin/env python
import sys
def usage():
prg = sys.argv[0]
print "Usage: %s [-L size] FileSystemPath SnapshotPath" % prg
print "___or: %s -d SnapshotPath" % prg
sys.exit(2)
class snapshotError(Exception):
pass
from commands import getstatusoutput
def do_or_die( cmd ):
stat,msg = getstatusoutput( cmd )
if stat:
raise snapshotError( msg )
return msg
from os import path
GET_LV_ATTR = '/usr/sbin/lvs --noheadings -o lv_attr %s'
CREATE_SS = '/usr/sbin/lvcreate --size %s --snapshot --name %s %s'
REMOVE_LV = '/usr/sbin/lvremove -f %s'
LOAD_SS_MOD = '/sbin/modprobe dm-snapshot'
class Volume(object):
"""A mounted logical-volume"""
def __init__( self, dir ):
""" Read /proc/mounts to determine the device and file-system type.
Read /etc/mtab to get the mount options.
"""
self.dev = None
for line in open( '/proc/mounts' ).readlines():
tokens = line.split()[:3]
if tokens[1] == dir:
self.attr = do_or_die( GET_LV_ATTR % tokens[0] ).strip()
self.dev, self.mnt, self.fs = tokens
break
if not self.dev:
raise snapshotError( '"%s" not a mount point' % dir)
self.opts = None
for line in open( '/etc/mtab' ).readlines():
tokens = line.split()[:4]
if tokens[1] == dir:
self.opts = tokens[3]
break
def take_snapshot( self, size, ss_mnt ):
# Require that this is a primary logical-volume
if self.attr[0] not in '-o':
raise snapshotError('"%s" not a primary logical-volume'
% self.dev
)
# Ensure that the snapshot kernel-module is loaded
do_or_die( LOAD_SS_MOD )
# Change option "rw" to "ro"
if self.opts:
opts = ','.join( [ s == 'rw' and 'ro' or s
for s in self.opts.split(',')
]
)
else:
opts = 'ro'
# Add options for xfs
if self.fs == 'xfs':
opts = ','.join( [ opts, 'nouuid' ] )
# Create the snapshot and its mount point, then mount it.
# Use the prefix SS_ for the name of the snapshot
head, tail = path.split( self.dev )
ss_name = 'SS_' + tail
ss_dev = path.join( head, ss_name )
print do_or_die( CREATE_SS % (size, ss_name, self.dev) )
# Release the snapshot if mkdir or mount fail
try:
print do_or_die( '/bin/mkdir -v -p %s' % ss_mnt )
cmd = '/bin/mount -v -r -t %s -o %s %s %s' \
% (self.fs, opts, ss_dev, ss_mnt)
print cmd
print do_or_die( cmd )
except:
print do_or_die( REMOVE_LV % ss_dev )
raise
def release_snapshot( self ):
# Require that this is a snapshot logical-volume"""
if self.attr[0] not in 'sS':
raise snapshotError( '"%s" not a snapshot logical-volume' )
do_or_die( '/bin/umount %s' % self.mnt )
do_or_die( REMOVE_LV % self.dev )
self.dev = None
do_or_die( 'rmdir --ignore-fail-on-non-empty %s' % self.mnt )
self.mnt = None
from getopt import getopt, GetoptError
def main():
try:
opts, args = getopt( sys.argv[1:], 'L:d' )
except GetoptError:
usage()
nargs = len( args )
delete = False
size = '2G' # Default size for COW space
for opt, parm in opts:
if opt == "-L":
size = parm
elif opt == "-d":
delete = True
try:
if delete:
if nargs != 1 :
usage()
Volume( args[0] ).release_snapshot()
else:
if nargs != 2:
usage()
Volume( args[0] ).take_snapshot( size, args[1] )
except snapshotError, msg:
print "ERROR:", msg
sys.exit(1)
if __name__ == "__main__":
main()
------------------------------------------------------------------------------
BlackBerry® DevCon Americas, Oct. 18-20, San Francisco, CA
http://p.sf.net/sfu/rim-devcon-copy2
_______________________________________________
Bacula-users mailing list
Bacula-users AT lists.sourceforge DOT net
https://lists.sourceforge.net/lists/listinfo/bacula-users
|