avoid multiple time zones
[distro-setup] / btrbk-run
old mode 100755 (executable)
new mode 100644 (file)
index 0d68028..f0f16bd
--- a/btrbk-run
+++ b/btrbk-run
@@ -14,7 +14,6 @@
 # limitations under the License.
 
 
-# todo: remove old leaf subvols, like keep up to 1 month or something.
 # todo: if we cancel in the middle of a btrfs send, then run again immediately, the received subvolume doesn't get a Received UUID: field, and we won't mount it. Need to figure out a solution that will fix this.
 
 set -eE -o pipefail
@@ -23,46 +22,65 @@ trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
 [[ $EUID == 0 ]] || exec sudo -E "$BASH_SOURCE" "$@"
 
 usage() {
+  cat <<'EOF'
+btrbk-run [OPTIONS]
+usually -t TARGET_HOST or -s SOURCE_HOST
+
+Note, at source location, intentionally not executable, run and read
+install-my-scripts.
+
+EOF
   echo "top of script file:"
   sed -n '1,/^[# ]*end command line/{p;b};q' "$0"
   exit $1
 }
 
-script_dir=$(dirname $(readlink -f "$BASH_SOURCE"))
+# latest $MAIL_HOST
+if [[ -e /b/bash_unpublished/source-semi-priv ]]; then
+  source /b/bash_unpublished/source-semi-priv
+fi
 
 # note q is owned by root:1000
-# note p/m is owned 1000:1000 and chmod 700
-
 
 mountpoints=()
 
 rsync_mountpoint=/q
 
+# default options
 conf_only=false
 dry_run=false # mostly for testing
-resume_arg=
 rate_limit=no
-verbose=false
+verbose=true; verbose_arg=-v
+progress_arg="--progress"
+pull_reexec=false
 
 default_args_file=/etc/btrbk-run.conf
 if [[ -s $default_args_file ]]; then
   set -- $(< $default_args_file) "$@"
+  echo "$0: warning: default btrbk-run options set in $default_args_file (sleeping 5 seconds):"
+  cat $default_args_file
+  sleep 5
 fi
 
-temp=$(getopt -l help cl:m:nprt:vh "$@") || usage 1
+orig_args=("$@")
+temp=$(getopt -l pull-reexec,help cl:m:nps:t: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 ;;
+    # bytes per second, suffix k m g
     -l) rate_limit=$2; shift 2 ;;
+    # Comma separated mountpoints to backup. This has defaults set below.
     -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 ;;
-    # empty is valid for just doing local snapshot. we have default hosts
-    # we will populate
+    --pull-reexec) pull_reexec=true; shift ;;
+    -q) verbose=false; verbose_arg=; progress_arg=; shift ;;
+    # source host to receive a backup from
+    -s) source=$2; shift 2 ;;
+    # target hosts to send to. 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 ;;
@@ -71,16 +89,33 @@ while true; do
   esac
 done
 
-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
+# usefull commands are resume and archive
+cmd_arg=${1:-run}
+
+if [[ -v targets && $source ]]; then
+  echo "$0: error: -t and -s are mutually exclusive" >&2
+  exit 1
+fi
+
+# pull_reexec stops us from getting into an infinite loop if there is some
+# kind of weird problem
+if ! $pull_reexec && [[ $source ]]; then
+  tmpf=$(mktemp)
+  scp $source:/a/bin/distro-setup/btrbk-run $tmpf
+  if diff -q $tmpf $BASH_SOURCE; then
+    echo "$0: found newer version on host $source. reexecing"
+    install -T $tmpf /usr/local/bin/btrbk-run
+    /usr/local/bin/btrbk-run --pull-reexec "${orig_args[@]}"
+  fi
 fi
 
-echo -e "$0: options: conf_only=$conf_only\ndry_run=$dry_run\nresume_arg=$resume_arg\nrate_limit=$rate_limit\nverbose=$verbose"
+
+echo -e "$0: options: conf_only=$conf_only\ndry_run=$dry_run\nrate_limit=$rate_limit\nverbose=$verbose\ncmd_arg=$cmd_arg"
+### end options parsing
+
 
 # set default targets
-if [[ ! -v targets ]]; then
+if [[ ! -v targets && ! $source ]]; then
   case $HOSTNAME in
     x2|kw)
       if [[ $HOSTNAME == "$MAIL_HOST" ]]; then
@@ -105,37 +140,46 @@ if [[ ! -v targets ]]; then
   esac
 fi
 
-echo "targets: ${targets[*]}"
+if [[ -v targets ]]; then
+  echo "targets: ${targets[*]}"
+fi
 
+if [[ $source ]]; then
+  echo "source: $source"
+fi
 
 
-# set default mountpoints
-case $HOSTNAME in
-  frodo)
-    prospective_mps=(/i)
-    ;;
-  *)
-    prospective_mps=(/a /q)
-    if [[ $HOSTNAME == "$MAIL_HOST" ]]; then
-      prospective_mps+=(/o)
+if [[ $mountpoints ]]; then
+  for mp in ${mountpoints[@]}; do # default mountpoints to sync
+    if [[ -e /nocow/btrfs-stale/$mp ]]; then
+      echo "$0: error: $mp is stale, mount-latest-subvol first"
+      exit 1
     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
+  done
+else
+  # set default mountpoints
+  case $HOSTNAME in
+    # no remote backups atm. note, if we do enable this, configuration below will need some changes.
+    #  frodo)
+    #    prospective_mps=(/i)
+    #    ;;
+    *)
+      prospective_mps=(/a /q)
+      if [[ $HOSTNAME == "$MAIL_HOST" ]]; then
+        prospective_mps+=(/o)
+      fi
+      ;;
+  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[*]}"
 
@@ -147,21 +191,7 @@ rsync-dirs() {
   m rsync $dry_run_arg -ahi --relative --delete "$path" "root@$host:/"
 }
 
-vol-conf() {
-  cat >>/etc/btrbk.conf <<EOF
-volume $vol
-EOF
-}
-sub-conf() {
-  cat >>/etc/btrbk.conf <<EOF
-subvolume $sub
-EOF
-}
-tg-conf() {
-  cat >>/etc/btrbk.conf <<EOF
-target send-receive ssh://$tg$vol/btrbk
-EOF
-}
+
 m() { printf "%s: %s\n" "${0##*/}" "$*";  "$@"; }
 
 
@@ -184,8 +214,9 @@ ssh_identity /root/.ssh/home
 # transaction info.
 transaction_syslog local7
 
-# 20%ish speedup[]
-stream_buffer 512m
+# note, i had this because man said 20% speedup, but ran into
+# this issue, https://github.com/digint/btrbk/issues/275
+#stream_buffer 512m
 
 # so we only run one at a time
 lockfile                   /var/lock/btrbk.lock
@@ -214,31 +245,37 @@ EOF
 
 
 
-for tg in ${targets[@]}; do
-  # for an initial run, btrbk requires the dir to exist.
-  # also use this opportunity to kill emacs, because it doesn't
-  # notice that the file has changed out from underneath it
-  ssh root@$tg mkdir -p /mnt/root/btrbk
+# for an initial run, btrbk requires the dir to exist.
+mkdir -p /mnt/root/btrbk
+local_zone=$(date +%z)
+for h in ${targets[@]} $source; do
+  zone=$(ssh root@$h "mkdir -p /mnt/root/btrbk; date +%z")
+  if [[ $zone != $local_zone ]]; then
+    echo "error: error. dont confuse yourself with multiple time zones. $h has different timezone than localhost" >&2
+    exit 1
+  fi
 done
 
 
+
+vol=/mnt/root
 for m in ${mountpoints[@]}; 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
+  sub=${m##*/}
+  if [[ $source ]]; then
+    cat >>/etc/btrbk.conf <<EOF
+volume ssh://$source$vol
+subvolume $sub
+target send-receive $vol/btrbk
+EOF
   else
-    vol=/mnt/root
-    vol-conf
-    sub=${m##*/}
-    sub-conf
+    cat >>/etc/btrbk.conf <<EOF
+volume $vol
+subvolume $sub
+EOF
     for tg in ${targets[@]}; do
-      tg-conf
+      cat >>/etc/btrbk.conf <<EOF
+target send-receive ssh://$tg$vol/btrbk
+EOF
     done
   fi
 done
@@ -252,19 +289,30 @@ if $conf_only; then
   exit
 fi
 
+
+
 if $dry_run; then
-  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.
-  m btrbk $verbose_arg $progress_arg $resume_arg run
+  m btrbk -v -n $cmd_arg
+  exit 0
+elif [[ $cmd_arg == archive ]]; then
+  if [[ $source ]]; then
+    m btrbk $verbose_arg $progress_arg $cmd_arg ssh://$source$vol $vol
+  else
+    for tg in ${targets[@]}; do
+      m btrbk $verbose_arg $progress_arg $cmd_arg $vol ssh://$tg$vol
+    done
+  fi
+  exit 0
 fi
+# -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.
+m btrbk $verbose_arg $progress_arg $cmd_arg
 
 # 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)
+      li|lk)
         for x in /p/c/machine_specific/*.hosts; do
           if grep -qxF $tg $x; then
             dir=${x%.hosts}
@@ -276,11 +324,13 @@ if mountpoint $rsync_mountpoint >/dev/null; then
   done
 fi
 
-if ! $dry_run; then
-  m $script_dir/mount-latest-remote ${targets[@]}
+/a/bin/distro-setup/install-my-scripts
+if [[ $source ]]; then
+  m mount-latest-subvol
+else
+  m /a/exe/mount-latest-remote ${targets[@]}
 fi
 
-
 # todo: move variable data we don't care about backing up
 # to /nocow and symlink it.