From a8f65652866003814b6f2c79bec0165beee24ab9 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Fri, 19 Mar 2010 21:26:24 +0100 Subject: [PATCH] Add a framework for source host backends. This is just the framework, there are no backends defined yet and no handlers that use it. --- lib/Makefile.am | 2 +- lib/backend.in | 162 +++++++++++++++++++++++++++++++++++++++++++++ src/backupninja.in | 6 +- 3 files changed, 168 insertions(+), 2 deletions(-) create mode 100644 lib/backend.in diff --git a/lib/Makefile.am b/lib/Makefile.am index 2a19969..df8ed61 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,4 +1,4 @@ -pkglib_SCRIPTS = easydialog parseini tools vserver array +pkglib_SCRIPTS = easydialog parseini tools vserver array backend CLEANFILES = $(pkglib_SCRIPTS) diff --git a/lib/backend.in b/lib/backend.in new file mode 100644 index 0000000..0c130f2 --- /dev/null +++ b/lib/backend.in @@ -0,0 +1,162 @@ +# -*- mode: sh; sh-basic-offset: 3; indent-tabs-mode: nil; -*- +# vim: set filetype=sh sw=3 sts=3 expandtab autoindent: + +defined_backends=() +available_backends=() + +function init_backends () { + for backend in "${defined_backends[@]}"; do + . "$libdirectory/backends/$backend" + if "backend_${backend}_init"; then + append available_backends "$backend" + debug "Backend '$backend' is available on this system" + else + debug "Backend '$backend' is not available on this system" + fi + done +} + +function init_source_hosts () { + # Use our first argument as the name of a configuration parameter to + # load the hosts from, or use the "hosts" parameter if nothing was + # passed. If the parameter is empty, use "localhost". + getconf_words "hosts" "local:" + # Allow the default backend variable to be overridden in this + # handler's configuration, but fall back to the global default + # backend. We use printconf instead of getconf to prevent the global + # $default_backend from getting clobbered. + local_default_backend=`printconf "default_backend" $default_backend` + + # Check to see if the default backend is valid (don't check + # availability yet, though) + if [ -n "$local_default_backend" ] && ! backend_defined "$local_default_backend"; then + fatal "Default backend '$local_default_backend' does not exist" + fi + + local hostspec + for hostspec in "${hosts[@]}"; do + + # Find the backend + local backend=`backend_for_hostspec "$hostspec"` + if [ -z "$backend" ]; then + if [ -z "$local_default_backend" ]; then + fatal "No default backend set and no explicit backend in hostspec '$hostspec'" + else + backend=$local_default_backend + fi + fi + + # Check if the backend is valid and available + if ! backend_defined "$backend"; then + fatal "Backend '$backend' does not exist" + elif ! backend_available "$backend"; then + fatal "Backend '$backend' is not available on this system" + fi + + # Check if the host is available + local reason + local host=`host_for_hostspec "$hostspec"` + if ! "backend_${backend}_host_available" "$host" reason; then + fatal "Host '$hostspec' is not available: $reason" + fi + + # Everything is ok, we can run on this host! + done; +} + +# Run the function pointed to by $1 for each of the source hosts defined +# in the configuration. Sets up the current backend and source host +# variables, so source_run & friends can be used. Also sets up the $root +# variable to point to the current source host's root filesystem (with +# no trailing /). +# This function should only be used after calling init_source_hosts. +function run_for_source_hosts () { + # $hosts will have been filled by init_source_hosts + for hostspec in "${hosts[@]}"; do + current_backend=`backend_for_hostspec "$hostspec"` + current_host=`host_for_hostspec "$hostspec"` + # Set the current source's root. + root=`"backend_${current_backend}_host_root" "$current_host"` + + info "Running on $current_backend:$current_host" + + # Run the actual backup handler + "$1" + done +} + +# Run the given command on the current source host. +# The command should be $1, with $2, $3, etc. being its arguments. +source_run () { + "backend_${current_backend}_run" "$@" +} + +function backend_available () { + in_array "$1" "${available_backends[@]}" +} + +function backend_defined () { + in_array "$1" "${defined_backends[@]}" +} + +function backend_for_hostspec () { + echo "$1" | sed 's/^\(\([^:]*\):\)\?\(.*\)$/\2/' +} + +function host_for_hostspec () { + echo "$1" | sed 's/^\(\([^:]*\):\)\?\(.*\)$/\3/' +} + + +# Replaces escape sequences in $1 with the proper values for the current +# backend. +# The result is put on stdout. If $2 is empty, values for the host are +# replaced. The following values are replaced: +# +# %% Literal % +# %h The short hostname (as returned by hostname -s) +# %H The full hostname (as returned by hostname --fqdn) +# %n The vserver name, or empty for the host +# %N The vserver name, or "host" for the host +# %v The vserver root directory, or empty for the host +# +# Note that the given vserver must be running! +# +function interpolate() { + path=$1 + + expr='' + # Allow backends to supply extra vars + vars=`"backend_${current_backend}_interpolate_vars"` + vars="h H s S r $vars" + for var in $vars; do + # Do indirect lookup of the value to replace + val=`interpolate_value "$var"` + # Escape slashes, backslashes and ampersands, since those have + # special meaning for sed (note that we need to double the \ + # twice, since it has special meaning to bash in the val= + # assignment, but also to sed. + val=`echo "$val" | sed 's#[/&\\\\]#\\\\&#g'` + # Add replacement pattern. The first part checks that there is + # an odd number of percent signs before the variable, so + # double % is properly left alone. + expr="${expr}s/\(\(^\|[^%]\)\(%%\)*\)%$var/\1$val/g;" + done + # Finally replace literal % signs + expr="${expr}s/%%/%/g" + + # Do the actual interpolation + echo $path | sed "$expr" +} + +function interpolate_value () { + case "$1" in + h) `source_run hostname -s`;; + H) `source_run hostname --fqdn`;; + s) echo "$current_host";; + S) echo "$current_backend:$current_host";; + r) echo "$root";; + # Not one of the defaults, ask the backend + *) "backend_${current_backend}_interpolate_value" "$current_host" "$1" + esac +} diff --git a/src/backupninja.in b/src/backupninja.in index f68a315..167ee7a 100755 --- a/src/backupninja.in +++ b/src/backupninja.in @@ -449,6 +449,7 @@ fi # include shared functions . $libdirectory/tools . $libdirectory/array +. $libdirectory/backend . $libdirectory/vserver setfile $conffile @@ -469,6 +470,7 @@ getconf when "Everyday at 01:00" defaultwhen=$when getconf logfile @localstatedir@/log/backupninja.log getconf usecolors "yes" +getconf default_backend getconf SLAPCAT /usr/sbin/slapcat getconf LDAPSEARCH /usr/bin/ldapsearch getconf RDIFFBACKUP /usr/bin/rdiff-backup @@ -484,7 +486,9 @@ getconf GZIP /bin/gzip getconf RSYNC /usr/bin/rsync getconf admingroup root -# initialize vservers support +init_backends + +# initialize legacy vservers support # (get config variables and check real vservers availability) init_vservers nodialog -- 2.30.2