aboutsummaryrefslogtreecommitdiff
path: root/lib/beam
diff options
context:
space:
mode:
Diffstat (limited to 'lib/beam')
-rw-r--r--lib/beam/.gitignore1
-rw-r--r--lib/beam/Makefile.am31
-rw-r--r--lib/beam/common.in135
-rwxr-xr-xlib/beam/fs.sh107
-rw-r--r--lib/beam/mysql.sh91
-rwxr-xr-xlib/beam/postgres.sh87
-rw-r--r--lib/beam/s3.sh85
7 files changed, 537 insertions, 0 deletions
diff --git a/lib/beam/.gitignore b/lib/beam/.gitignore
new file mode 100644
index 0000000..5621a6e
--- /dev/null
+++ b/lib/beam/.gitignore
@@ -0,0 +1 @@
+common.sh
diff --git a/lib/beam/Makefile.am b/lib/beam/Makefile.am
new file mode 100644
index 0000000..d490acb
--- /dev/null
+++ b/lib/beam/Makefile.am
@@ -0,0 +1,31 @@
+# This file is part of BEAM
+# Copyright (C) 2012 Sergey Poznyakoff
+#
+# BEAM is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# BEAM 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. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with BEAM. If not, see <http://www.gnu.org/licenses/>.
+
+libbackupdir=$(libdir)/beam
+libbackup_SCRIPTS=\
+ common.sh\
+ s3.sh\
+ fs.sh\
+ mysql.sh\
+ postgres.sh
+EXTRA_DIST=\
+ common.in\
+ s3.sh\
+ fs.sh\
+ mysql.sh\
+ postgres.sh
+DISTCLEANFILES=common.sh
+include $(top_srcdir)/Make.rules
diff --git a/lib/beam/common.in b/lib/beam/common.in
new file mode 100644
index 0000000..49b41eb
--- /dev/null
+++ b/lib/beam/common.in
@@ -0,0 +1,135 @@
+#! /bin/bash
+# This file is part of BEAM
+# Copyright (C) 2012 Sergey Poznyakoff
+#
+# BEAM is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# BEAM 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. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with BEAM. If not, see <http://www.gnu.org/licenses/>.
+
+# Force C locale
+LC_ALL=C
+export LC_ALL
+
+prologue_hook=
+epilogue_hook=
+
+# User configuration variables
+backup_tar_options=
+backup_suffix=
+backup_archive_dir=
+backup_snapshot_dir=
+backup_verbose=
+backup_logfile="/var/log/backup"
+
+error() {
+ echo >&2 $0: $*
+}
+
+logit() {
+ echo `date`: $*
+}
+
+abend() {
+ ec=$1
+ shift
+ error $@
+ exit $ec
+}
+
+tarcode() {
+ case $1 in
+ 0) echo "`date`: success";;
+ 1) echo "`date`: some files changed while being archived";;
+ 2) echo "`date`: fatal error occurred, but trying to continue anyway"
+ tarerror=$((tarerror + 1));;
+ *) echo "`date`: unexpected error code $1"
+ tarerror=$((tarerror + 1));
+ esac
+}
+
+load_config() {
+ local delayed_exit
+
+ test -z "$BEAM_CONFIG" && BEAM_CONFIG=@SYSCONFDIR@/beam.conf
+ if [ -r $BEAM_CONFIG ]; then
+ . $BEAM_CONFIG
+ else
+ abend 1 "configuration file $BEAM_CONFIG does not exist or is unreadable"
+ fi
+
+ if [ -z "$backup_items" ]; then
+ abend 1 "backup_items not specified"
+ fi
+
+ delayed_exit=
+ loaded_types=
+ for item in $backup_items
+ do
+ eval type=\$${item}_type
+ if [ -z "$type" ]; then
+ error "${item}_type not set"
+ delayed_exit=1
+ continue
+ fi
+
+ if echo "$loaded_types" | grep -wq $type; then
+ :
+ elif [ -x $libdir/${type}.sh ]; then
+ . $libdir/${type}.sh || delayed_exit=1
+ loaded_types="$loaded_files
+$type"
+ else
+ error "$libdir/${type}.sh not found"
+ delayed_exit=1
+ fi
+
+ ${type}_check $item || delayed_exit=1
+ done
+
+ test -n "$delayed_exit" && abend 1 "aborting"
+
+ tar_suffix=${backup_suffix:-.tar}
+
+ if [ -n "$backup_bucket_name" ]; then
+ . @LIBDIR@/beam/s3.sh
+ prologue_hook="$prologue_hook s3_mount"
+ fi
+}
+
+runhook() {
+ local hook_list
+
+ eval hook_list=\$$1
+ for hook in $hook_list
+ do
+ $hook
+ done
+}
+
+print_version() {
+ name=$(basename $0)
+ cat <<EOF
+$name (@PACKAGE_NAME@) @PACKAGE_VERSION@
+Copyright (C) 2012 Sergey Poznyakoff
+License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
+This is free software: you are free to change and redistribute it.
+There is NO WARRANTY, to the extent permitted by law.
+EOF
+ exit 0
+}
+
+wtf() {
+ l=`echo "${1#beam-}"|sed "s|.|.|g"`
+ s=$(echo " " | sed "s|$l|${1#beam-}|")
+ shift
+ echo " $s $@"
+}
diff --git a/lib/beam/fs.sh b/lib/beam/fs.sh
new file mode 100755
index 0000000..6d7d4c7
--- /dev/null
+++ b/lib/beam/fs.sh
@@ -0,0 +1,107 @@
+#! /bin/bash
+# This file is part of BEAM
+# Copyright (C) 2012 Sergey Poznyakoff
+#
+# BEAM is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# BEAM 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. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with BEAM. If not, see <http://www.gnu.org/licenses/>.
+
+# initdb item
+# Initializes snapshot for the given basename.
+initdb() {
+ local filename
+
+ if [ -n "$dry_run" ]; then
+ logit "initializing snapshot for $1"
+ return
+ fi
+
+ if [ $level -eq 0 ]; then
+ filename=$backup_snapshot_dir/$1-$week-$round-$level.db
+ test -r $filename && rm $filename
+ else
+ if [ $level -eq 1 ]; then
+ filename=$backup_snapshot_dir/$1-$week-0-0.db
+ else
+ filename=$backup_snapshot_dir/$1-$week-$round-$((level - 1)).db
+ fi
+ if [ -r $filename ]; then
+ cp $filename $backup_snapshot_dir/$1-$week-$round-$level.db
+ else
+ abend 1 "previous snapshot file $filename not found; cannot backup at level $level"
+ exit 1
+ fi
+ fi
+}
+
+# fs_check item
+fs_check() {
+ local rc=0
+
+ eval root=\$${1}_dir
+ eval files=\$${1}_files
+
+ test -z "$root" && rc=1 && error "${1}_dir not set"
+ test -z "$files" && rc=1 && error "${1}_files not set"
+ return $rc
+}
+
+# fs_backup item
+fs_backup() {
+ local basename text root files
+
+ basename=$1-$week-$round-$level
+ eval text=\$${1}_text
+ eval root=\$${1}_dir
+ eval files=\$${1}_files
+
+ test -z "$root" && abend 1 "${1}_dir not set"
+ test -z "$files" && abend 1 "${1}_files not set"
+ test -z "$text" && text="$1"
+ initdb $1
+ logit "backing up $text ($basename.$tar_suffix)"
+ $dry_run tar $verbose $taroptions \
+ -f $backup_archive_dir/$basename.$tar_suffix \
+ --listed=$backup_snapshot_dir/$basename.db \
+ -C $root $files
+ tarcode $?
+}
+
+# fs_restore item
+fs_restore() {
+ local i text root files tarcommand
+
+ eval text=\$${1}_text
+ eval root=\$${1}_dir
+ eval files=\$${1}_files
+
+ test -z "$root" && abend 1 "${1}_dir not set"
+ test -z "$files" && abend 1 "${1}_files not set"
+ test -z "$text" && text="$1"
+
+ tarcommand="tar $verbose $taroptions -C $root --listed-incremental=/dev/null -f"
+
+ logit "restoring $text"
+ logit "restoring from level 0 backup"
+
+ $dry_run $tarcommand $backup_archive_dir/$1-$week-0-0.$tar_suffix
+ tarcode $?
+
+ for i in $(seq 1 $level)
+ do
+ logit "restoring from the $round/$i backup"
+ $dry_run $tarcommand $backup_archive_dir/$1-$week-$round-$i.tar.bz2
+ tarcode $?
+ done
+ logit "finished restoring $text"
+}
+
diff --git a/lib/beam/mysql.sh b/lib/beam/mysql.sh
new file mode 100644
index 0000000..c33adb0
--- /dev/null
+++ b/lib/beam/mysql.sh
@@ -0,0 +1,91 @@
+#! /bin/bash
+# This file is part of BEAM
+# Copyright (C) 2012 Sergey Poznyakoff
+#
+# BEAM is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# BEAM 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. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with BEAM. If not, see <http://www.gnu.org/licenses/>.
+
+# mysql_check item
+mysql_check() {
+ eval database=\$${1}_database
+ test -z "$database" && error "${1}_database not set" && return 1
+ return 0
+}
+
+# mysql_backup item
+mysql_backup() {
+ local database
+
+ logit "backing up MySQL database $1"
+ eval database=\$${1}_database
+ test -z "$database" && abend 1 "${1}_database not set"
+ cmd="mysqldump"
+ eval defaults_file=\$${1}_defaults_file
+ if [ -n "$defaults_file" ]; then
+ cmd="$cmd --defaults-file=$defaults_file"
+ fi
+ cmd="$cmd --add-drop-database --databases"
+ if [ -z "$dry_run" ]; then
+ $cmd $database > $backup_snapshot_dir/$1-$week-$round-$level
+ else
+ echo "$cmd $database > $backup_snapshot_dir/$1-$week-$round-$level"
+ fi
+
+ if [ $? -ne 0 ]; then
+ tarerror=$((tarerror + 1))
+ echo >&2 "`date`: failed"
+ else
+ echo "`date`: creating $1-$week-$round-$level.$tar_suffix"
+ $dry_run tar $verbose $taroptions \
+ -f $backup_archive_dir/$1-$week-$round-$level.$tar_suffix \
+ -C $backup_snapshot_dir $1-$week-$round-$level
+ tarcode $?
+ $dry_run rm $backup_snapshot_dir/dbdump-$week-$round-$level
+ fi
+}
+
+mysql_restore() {
+ local u database
+
+ eval database=\$${1}_database
+ logit "restoring MySQL database $database"
+ u=$(umask)
+ trap "umask $u" 1 2 3 13 15
+ umask 077
+ $dry_run tar $verbose $taroptions \
+ -f $backup_archive_dir/$1-$week-$round-$level.$tar_suffix
+ e=$?
+ tarcode $e
+ if [ $e -eq 0 ]; then
+ logit "restoring database from the dump"
+ cmd="mysql -A --batch"
+ eval defaults_file=\$${1}_defaults_file
+ if [ -n "$defaults_file" ]; then
+ cmd="$cmd --defaults-file=$defaults_file"
+ fi
+ if [ -n "$dry_run" ]; then
+ echo "$cmd < $1-$week-$round-$level"
+ elif [ -r $1-$week-$round-$level ]; then
+ $cmd < $1-$week-$round-$level > db-$1.log
+ if grep ERROR db-$1.log >/dev/null; then
+ error "errors occurred during restore; see db-$1.log for details"
+ error "dump preserved in file $1-$week-$round-$level"
+ tarerror=$((tarerror + 1))
+ else
+ rm $1-$week-$round-$level
+ fi
+ fi
+ fi
+ umask $u
+ trap - 1 2 3 13 15
+}
diff --git a/lib/beam/postgres.sh b/lib/beam/postgres.sh
new file mode 100755
index 0000000..0072da6
--- /dev/null
+++ b/lib/beam/postgres.sh
@@ -0,0 +1,87 @@
+#! /bin/bash
+# This file is part of BEAM
+# Copyright (C) 2012 Sergey Poznyakoff
+#
+# BEAM is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# BEAM 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. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with BEAM. If not, see <http://www.gnu.org/licenses/>.
+
+# postgres_check item
+postgres_check() {
+ eval database=\$${1}_database
+ test -z "$database" && error "${1}_database not set" && return 1
+ return 0
+}
+
+# postgres_backup item
+postgres_backup() {
+ local database
+
+ logit "backing up PostgreSQL $1"
+ eval database=\$${1}_database
+ test -z "$database" && abend 1 "${1}_database not set"
+ if [ -z "$dry_run" ]; then
+ su postgres -c "pg_dump $verbose $database" > $backup_snapshot_dir/$1-$week-$round-$level
+ else
+ echo "su postgres -c \"pg_dump $verbose $database\" > $backup_snapshot_dir/$1-$week-$round-$level"
+ fi
+
+ if [ $? -ne 0 ]; then
+ tarerror=$((tarerror + 1))
+ echo >&2 "`date`: failed"
+ else
+ echo "`date`: creating $1-$week-$round-$level.$tar_suffix"
+ $dry_run tar $verbose $taroptions \
+ -f $backup_archive_dir/$1-$week-$round-$level.$tar_suffix \
+ -C $backup_snapshot_dir $1-$week-$round-$level
+ tarcode $?
+ $dry_run rm $backup_snapshot_dir/dbdump-$week-$round-$level
+ fi
+}
+
+postgres_restore() {
+ local u database
+
+ eval database=\$${1}_database
+ logit "restoring PostgreSQL database $database"
+ u=$(umask)
+ trap "umask $u" 1 2 3 13 15
+ umask 077
+ $dry_run tar $verbose $taroptions \
+ -f $backup_archive_dir/$1-$week-$round-$level.$tar_suffix
+ e=$?
+ tarcode $e
+ if [ $e -eq 0 ]; then
+ logit "restoring database from the dump"
+ if [ -n "$dry_run" ]; then
+ cat <<-EOT
+ su postgres -c "dropdb $database"
+ su postgres -c "createdb $database"
+ su postgres -c "psql -d $database -f $1-$week-$round-$level"
+ rm $1-$week-$round-$level
+EOT
+ elif [ -r $1-$week-$round-$level ]; then
+ su postgres -c "dropdb $database"
+ su postgres -c "createdb $database"
+ su postgres -c "psql -d $database -f $1-$week-$round-$level" > db-$1.log
+ if grep ERROR db-$1.log >/dev/null; then
+ error "errors occurred during restore; see db-$1.log for details"
+ error "dump preserved in file $1-$week-$round-$level"
+ tarerror=$((tarerror + 1))
+ else
+ rm $1-$week-$round-$level
+ fi
+ fi
+ fi
+ umask $u
+ trap - 1 2 3 13 15
+}
diff --git a/lib/beam/s3.sh b/lib/beam/s3.sh
new file mode 100644
index 0000000..5f7235c
--- /dev/null
+++ b/lib/beam/s3.sh
@@ -0,0 +1,85 @@
+# This file is part of BEAM -*- shell-script -*-
+# Copyright (C) 2012 Sergey Poznyakoff
+#
+# BEAM is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# BEAM 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. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with BEAM. If not, see <http://www.gnu.org/licenses/>.
+
+# The configuration variable "backup_bucket_name" must contain the name
+# of the s3 bucket to use.
+
+# Raw bucket is mounted to /mnt/s3backer
+test -z "$backup_mp_s3backer" && backup_mp_s3backer=/mnt/s3backer
+# The actual file system is mounted to /mnt/s3
+test -z "$backup_mp" && backup_mp_s3=/mnt/s3
+
+# This variable is populated by s3_mount and is used by s3_unmount to unmount
+# s3-backed file system.
+umount_list=""
+
+s3_mount() {
+ # Make sure both mountpoints exist
+ test -d $backup_mp_s3backer || mkdir $backup_mp_s3backer
+ test -d $backup_mp_s3 || mkdir $backup_mp_s3backer
+
+# Sample mount output, split into several lines:
+# http://finox-backup-fs.s3.amazonaws.com/ on /mnt/s3backer type fuse.s3backer
+# (rw,nosuid,nodev,allow_other,default_permissions)
+ set -- $(mount -tfuse.s3backer |
+ awk '/https?:\/\/'$backup_bucket_name'/ { print $3 }')
+ if test -z "$1"; then
+ $dry_run s3backer $backup_s3backer_options \
+ $backup_bucket_name $backup_mp_s3backer ||
+ abend 1 "unable to mount $backup_bucket_name"
+ umount_list="$backup_mp_s3backer"
+ else
+ backup_mp_s3backer=$1
+ fi
+ set -- $(mount | grep "^${backup_mp_s3backer}/file" | awk '{ print $3 }')
+ if test -z "$1"; then
+ case $(basename $0) in
+ beam-restore|restore) mountopt=",ro";;
+ beam-backup|backup) mountopt=",rw,data=writeback";;
+ beam-s3) ;;
+ *) error "called as $0: assuming default mount options"
+ esac
+ # NOTE: For ext4 add the journal_async_commit option.
+ $dry_run mount -oloop$mountopt $backup_mp_s3backer/file $backup_mp_s3 ||
+ abend 1 "unable to mount $backup_mp_s3backer/file"
+ umount_list="$backup_mp_s3 $umount_list"
+ else
+ backup_mp_s3=$1
+ fi
+ epilogue_hook="s3_unmount $epilogue_hook"
+}
+
+s3_getmpoint()
+{
+ case $1 in
+ backer)
+ mount -tfuse.s3backer |
+ awk '/https?:\/\/'$backup_bucket_name'/ { print $3 }';;
+ s3)
+ mount | grep "^${backup_mp_s3backer}/file" | awk '{ print $3 }';;
+ *)
+ abent 1 "invalid usage of getmpoint"
+ esac
+}
+
+s3_unmount()
+{
+ for id in s3 backer
+ do
+ mpoint=$(s3_getmpoint $id)
+ test -n "$mpoint" && umount $mpoint
+ done
+}

Return to:

Send suggestions and report system problems to the System administrator.