#! /usr/bin/env bash # Upload new or upgrade existing machine subvolume on a Build OS build host. # # -k - keep the old subvolume on the target host # -u - target user instead of build # -d - target machines directory instead of /build/machines/default # # - build host to upload to (as user build by default) # - machine subvolume to upload # - previous machine subvolume (btrfs send -p) # usage="usage: $0 [] []" owd="$(pwd)" trap "{ cd '$owd'; exit 1; }" ERR set -o errtrace -o pipefail # Trap in functions. # Fail if any pipe command fails. function info () { echo "$*" 1>&2; } function error () { info "$*"; exit 1; } keep=false user=build machines=/build/machines/default while [ "$#" -gt 0 ]; do case "$1" in -k) keep=true shift ;; -u) shift user="$1" shift ;; -d) shift machines="$1" shift ;; -*) error "unknown option: $1" ;; *) break ;; esac done host="$1" newsv="${2%/}" oldsv="${3%/}" if [ -z "$host" -o -z "$newsv" ]; then error "$usage" fi host="$user@$host" newsv_name="$(sed -n -re 's%^(.*/)?([^/]+)$%\2%p' <<<"$newsv")" oldsv_name="$(sed -n -re 's%^(.*/)?([^/]+)$%\2%p' <<<"$oldsv")" if [ -z "$newsv_name" ]; then error "unable to extract subvolume name from '$newsv'" fi if [ -n "$oldsv" -a -z "$oldsv_name" ]; then error "unable to extract subvolume name from '$oldsv'" fi # Get the machine link (-

) and name. # mlink="$(sed -n -re 's/^(.+-[0-9]+)\.[0-9]+$/\1/p' <<<"$newsv_name")" mname="$(sed -n -re 's/^(.+)-[0-9]+$/\1/p' <<<"$mlink")" if [ -z "$mlink" -o -z "$mname" ]; then error "unable to extract machine link/name from '$newsv'" fi # Subvolume paths on target host. # newsv_host="$machines/$mname/$newsv_name" oldsv_host="$machines/$mname/$oldsv_name" # Make sure subvolumes are read-only. # function make_ro () # { local r; r="$(btrfs property get -ts "$1" ro)" if [ "$r" != "ro=true" ]; then info "subvolume '$1' is read-write, changing to read-only" btrfs property set -ts "$1" ro true fi } make_ro "$newsv" if [ -n "$oldsv" ]; then make_ro "$oldsv" fi # btrfs send command # send=(btrfs send) if [ -n "$oldsv" ]; then send+=(-p "$oldsv") fi send+=("$newsv") set -x # Make sure the machine directory exists. # ssh "$host" mkdir -p "$machines/$mname" # Send the snapshot over. # sudo "${send[@]}" | ssh "$host" sudo btrfs receive "$machines/$mname/" # Adjust machine ownership. # # Recent btrfs-progs require the force flag (-f) (Debian bug #1019377). # Turns out btrfs now strips the subvolume uuid if we make it rw, which # will prevent it from being used as a base for incremental send. # # @@ Maybe we should just keep the original as is (for incremental send) # and make another copy where we change the ownership? Note: will also # need to update remove-machine. # ssh "$host" sudo btrfs property set -f -ts "$newsv_host" ro false ssh "$host" sudo chown "$user:$user" "$newsv_host" ssh "$host" sudo chown "$user:$user" "$newsv_host/*" ssh "$host" btrfs property set -ts "$newsv_host" ro true # Atomically switch the current machine. # ssh "$host" "cd $machines/$mname && ln -s $newsv_name new-$mlink" ssh "$host" "cd $machines/$mname && mv -T new-$mlink $mlink" # Remove the old machine subvolume. # { set +x; } 2>/dev/null if [ -z "$oldsv" -o "$keep" = true ]; then exit 0 fi set -x ssh "$host" btrfs property set -ts "$oldsv_host" ro false ssh "$host" btrfs subvolume delete "$oldsv_host"