#! /usr/bin/env bash # Upload new or upgrade existing machine subvolume on a Build OS build host. # # -k - keep the old subvolume on the build host # # - build host to upload to (as user 'build') # - machine subvolume to upload # - previous machine subvolume (btrfs send -p) # usage="usage: $0 [] []" machines=/build/machines/default owd="$(pwd)" trap "{ cd '$owd'; exit 1; }" ERR set -o errtrace # Trap in functions. function info () { echo "$*" 1>&2; } function error () { info "$*"; exit 1; } keep=false while [ "$#" -gt 0 ]; do case "$1" in -k) keep=true 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="build@$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 build host. # newsv_host="$machines/$mname/$newsv_name" oldsv_host="$machines/$mname/$oldsv_name" # Make sure subvolumes are read-only. # function check_ro () # { local r; r="$(btrfs property get -ts "$1" ro)" if [ "$r" != "ro=true" ]; then info "subvolume '$1' is not read-only; to change, run:" info " btrfs property set -ts $1 ro true" exit 1 fi } check_ro "$newsv" if [ -n "$oldsv" ]; then check_ro "$oldsv" fi # btrfs send command # send=(sudo 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. # ssh "$host" sudo btrfs property set -ts "$newsv_host" ro false ssh "$host" sudo chown build:build "$newsv_host" ssh "$host" sudo chown build:build "$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"