X-Git-Url: https://iankelling.org/git/?a=blobdiff_plain;f=btrbk-run;h=5ff83260022c20d1eeec2217ae8392b61653b69d;hb=65351382939fa95fb1e05d7d83eb58d27c3c6133;hp=8cae3a79cb744f85edbd662fc192e7f6afdcaa85;hpb=9eeed9d8bd24850fe5e35d2c2f9be8608491bf70;p=distro-setup diff --git a/btrbk-run b/btrbk-run index 8cae3a7..5ff8326 100755 --- a/btrbk-run +++ b/btrbk-run @@ -1,9 +1,26 @@ #!/bin/bash +# Copyright (C) 2016 Ian Kelling + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +# todo: remove old leaf subvols, like keep up to 1 month or something. set -eE -o pipefail trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR [[ $EUID == 0 ]] || exec sudo -E "$BASH_SOURCE" "$@" + usage() { echo "top of script file:" sed -n '1,/^[# ]*end command line/{p;b};q' "$0" @@ -12,34 +29,129 @@ usage() { script_dir=$(dirname $(readlink -f "$BASH_SOURCE")) -# todo: finish figuring out fai / distro-setup -# initial fstab / subvol setup. +# note q is owned by root:1000 +# note p/m is owned 1000:1000 and chmod 700 + + +mountpoints=() + +rsync_mountpoint=/q conf_only=false dry_run=false # mostly for testing resume_arg= +rate_limit=no +verbose=false + +default_args_file=/etc/btrbk-run.conf +if [[ -s $default_args_file ]]; then + set -- $(< $default_args_file) "$@" +fi -temp=$(getopt -l help hcnrt: "$@") || usage 1 +temp=$(getopt -l help cl:m:nprt:vh "$@") || usage 1 eval set -- "$temp" while true; do case $1 in + # only creates the config file, does not run btrbk -c) conf_only=true; shift ;; + -l) rate_limit=$2; shift 2 ;; + -m) IFS=, mountpoints=($2); unset IFS; shift 2 ;; -n) dry_run=true; dry_run_arg=-n; shift ;; + -p) progress_arg="--progress"; shift ;; + # btrbk arg: Resume only. Skips snapshot creation. -r) resume_arg=-r; shift ;; - -t) IFS=, targets=($2); shift 2 ;; + # empty is valid for just doing local snapshot. we have default hosts + # we will populate + -t) IFS=, targets=($2); unset IFS; shift 2 ;; + -v) verbose=true; verbose_arg=-v; shift ;; -h|--help) usage ;; --) shift; break ;; *) echo "$0: Internal error!" ; exit 1 ;; esac done -read primary <<<"$@" + +if [[ -s $default_args_file ]]; then + echo "$0: warning: default btrbk-run options set in $default_args_file (sleeping 5 seconds):" + cat $default_args_file + sleep 5 +fi + +echo -e "$0: options: conf_only=$conf_only\ndry_run=$dry_run\nresume_arg=$resume_arg\nrate_limit=$rate_limit\nverbose=$verbose" + +# set default targets +if [[ ! -v targets ]]; then + case $HOSTNAME in + x2|fz) + if [[ $HOSTNAME == "$MAIL_HOST" ]]; then + targets=($HOME_DOMAIN) + fi + ;; + tp) + targets=(frodo) + if [[ $HOSTNAME == "$MAIL_HOST" ]]; then + if timeout -s 9 10 ssh x2 :; then + targets+=(x2) + fi + fi + ;; + frodo) + targets=() + ;; + *) + echo "$0: error: no default targets for this host, use -t" + exit 1 + ;; + esac +fi + +echo "targets: ${targets[*]}" + + + +if (( ${#mountpoints[@]} )); then + for mp in ${mountpoints[@]}; do + if [[ -e /nocow/btrfs-stale/$mp ]]; then + echo "$0: warning: $mp stale. Sleeping for 3 seconds in case you want to cancel." + sleep 3 + fi + done +else # set default mountpoints + case $HOSTNAME in + frodo) + prospective_mps=(/i) + ;; + *) + prospective_mps=(/a /q) + if [[ $HOSTNAME == "$MAIL_HOST" ]]; then + prospective_mps+=(/o) + fi + ;; + esac + case ${targets[0]} in + kw|kww) + prospective_mps=(/a) + ;; + esac + + for mp in ${prospective_mps[@]}; do # default mountpoints to sync + if [[ -e /nocow/btrfs-stale/$mp ]]; then + echo "$0: warning: $mp stale, not adding to default mountpoints" + continue + fi + if awk '{print $2}' /etc/fstab | grep -xF $mp &>/dev/null; then + mountpoints+=($mp) + fi + done +fi + +echo "mountpoints: ${mountpoints[*]}" ##### end command line parsing ######## rsync-dirs() { local host=$1 local path=$2 - rsync $dry_run_arg -ahi --relative --delete "$path" "root@$host:/" + m rsync $dry_run_arg -ahi --relative --delete "$path" "root@$host:/" } vol-conf() { @@ -57,15 +169,22 @@ tg-conf() { target send-receive ssh://$tg$vol/btrbk EOF } - +m() { printf "%s: %s\n" "${0##*/}" "$*"; "$@"; } if ! which btrbk &>/dev/null; then echo "$0: error: no btrbk binary found" fi -cat >/etc/btrbk.conf <<'EOF' -ssh_identity /root/.ssh/id_rsa +cat >/etc/btrbk.conf </dev/null; then - mountpoints+=(/p) -fi # if our mountpoints are from stale snapshots, # it doesn't make sense to do a backup. check-subvol-stale ${mountpoints[@]} || exit 1 -if [[ ! $targets ]]; then - case $HOSTNAME in - tp|x2) - if ! timeout -s 9 10 ssh frodo :; then - targets=($HOME_DOMAIN) - fi - ;; - esac - targets=(frodo) -fi - - -# for i, we just do a 1 way sync from master to backup, -# and manually manage any changes to that. -do_i=false for tg in ${targets[@]}; do # for an initial run, btrbk requires the dir to exist ssh root@$tg mkdir -p /mnt/root/btrbk - if [[ $tg == frodo && $HOSTNAME == treetowl ]]; then - do_i=true - fi done -vol=/mnt/root -vol-conf for m in ${mountpoints[@]}; do - sub=${m##*/} - sub-conf - for tg in ${targets[@]}; do + # for /i, some special cases. there is just one static target and direction. + if [[ $m == /i ]]; then + vol=/mnt/iroot + vol-conf + sub=i + sub-conf + tg=frodo + vol=/mnt/root tg-conf - done + else + vol=/mnt/root + vol-conf + sub=${m##*/} + sub-conf + for tg in ${targets[@]}; do + tg-conf + done + fi done -if $do_i; then - vol=/mnt/iroot - vol-conf - sub=i - sub-conf - tg=frodo - vol=/mnt/root - tg-conf -fi - - # todo: umount first to ensure we don't have any errors # todo: do some kill fuser stuff to make umount more reliable -# todo: run this on a systemd timer on $primary, once per hour, -# and if primary is, change that timer over to primary, and make -# sure we mount the latest - if $conf_only; then @@ -161,15 +253,15 @@ if $conf_only; then fi if $dry_run; then - btrbk -n $resume_arg run + m btrbk -v -n $resume_arg run else # -q and just using the syslog option seemed nice, # but it doesn't show when a send has a parent and when it doesn't. - btrbk $resume_arg run + m btrbk $verbose_arg $progress_arg $resume_arg run fi -# if we have /p, rsync to targets without /p -if mountpoint /p >/dev/null; then +# if we have it, sync to systems which don't +if mountpoint $rsync_mountpoint >/dev/null; then for tg in ${targets[@]}; do case $tg in tp|li|lk) @@ -185,7 +277,7 @@ if mountpoint /p >/dev/null; then fi if ! $dry_run; then - $script_dir/mount-latest-remote ${targets[@]} + m $script_dir/mount-latest-remote ${targets[@]} fi