2022-11-19 08:34:22 +00:00
|
|
|
#!/usr/bin/env sh
|
|
|
|
|
2022-11-21 02:01:46 +00:00
|
|
|
nodes_file="nodes.txt"
|
2022-11-19 08:49:50 +00:00
|
|
|
### nodes.txt
|
2023-01-02 22:07:37 +00:00
|
|
|
# <origin host> <user> <ssh port> <timezone> <compressed flag>
|
|
|
|
# <mirror 1 host> <user> <ssh port> <zfs root>
|
|
|
|
# <mirror 2 host> <user> <ssh port> <zfs root>
|
2022-11-19 08:36:40 +00:00
|
|
|
# ...
|
|
|
|
|
2022-11-21 02:01:46 +00:00
|
|
|
datasets_file="datasets.txt"
|
2022-11-21 01:15:43 +00:00
|
|
|
### datasets.txt
|
2022-11-19 08:36:40 +00:00
|
|
|
# <dataset 1>
|
2023-01-02 22:07:37 +00:00
|
|
|
# <dataset 2>
|
2022-11-19 08:36:40 +00:00
|
|
|
# <dataset 3>
|
|
|
|
# ...
|
|
|
|
|
2023-01-02 22:07:37 +00:00
|
|
|
if [ ! -f $nodes_file ]; then echo "No nodes specified."; exit 2; fi
|
|
|
|
if [ ! -f $datasets_file ]; then echo "No datasets specified."; exit 3; fi
|
|
|
|
|
|
|
|
ZFS_SEND_OPTS="-R"
|
|
|
|
ZFS_SNAPSHOT_OPTS="-r"
|
|
|
|
ZFS_RECV_OPTS="-svu"
|
|
|
|
|
|
|
|
read LOCAL_HOST LOCAL_USER LOCAL_PORT LOCAL_TZ SEND_COMPRESSED < $nodes_file
|
|
|
|
case $SEND_COMPRESSED in
|
|
|
|
[tTyY]*) ZFS_SEND_OPTS="$ZFS_SEND_OPTS -c" ;;
|
|
|
|
esac
|
|
|
|
|
|
|
|
ORIGIN_PERMS="send,snapshot,hold"
|
2023-01-08 05:57:20 +00:00
|
|
|
MIRROR_PERMS="compression,receive,create"
|
2023-01-02 22:07:37 +00:00
|
|
|
|
|
|
|
GRAPH_DATASETS_RAW=`cat $datasets_file`
|
|
|
|
GRAPH_DATASETS=`for dataset in $GRAPH_DATASETS_RAW; do
|
|
|
|
case $dataset in
|
|
|
|
\#*) continue;;
|
|
|
|
esac
|
|
|
|
echo -n "$dataset "
|
|
|
|
done`
|
|
|
|
|
|
|
|
list_datasets()
|
2022-11-19 08:34:22 +00:00
|
|
|
{
|
2023-01-02 22:07:37 +00:00
|
|
|
for dataset in $GRAPH_DATASETS; do
|
|
|
|
zfs list -H $dataset
|
|
|
|
done
|
2022-11-19 08:34:22 +00:00
|
|
|
}
|
|
|
|
|
2023-01-02 22:07:37 +00:00
|
|
|
list_remote_datasets() {
|
|
|
|
while read addr user ssh_port zroot; do
|
|
|
|
echo "=== $user@$addr $zroot ==="
|
2022-11-24 03:56:12 +00:00
|
|
|
if [ $BG_TEST_MODE = "TRUE" ]; then
|
2023-01-02 22:07:37 +00:00
|
|
|
echo ssh -i ~/.ssh/id_rsa -o port=$ssh_port $user@$addr\
|
|
|
|
"sh -c 'for dataset in $GRAPH_DATASETS;
|
|
|
|
do zfs list -H $zroot/\$dataset;
|
|
|
|
done'"
|
|
|
|
else
|
|
|
|
ssh -i ~/.ssh/id_rsa -o port=$ssh_port $user@$addr \
|
|
|
|
"sh -c 'for dataset in $GRAPH_DATASETS;
|
|
|
|
do zfs list -H $zroot/\$dataset;
|
|
|
|
done';"
|
2022-11-24 03:56:12 +00:00
|
|
|
fi
|
2023-01-02 22:07:37 +00:00
|
|
|
done < sendnodes.tmp
|
2022-11-21 02:01:46 +00:00
|
|
|
}
|
|
|
|
|
2022-11-19 08:34:22 +00:00
|
|
|
get_latest_snapshot()
|
|
|
|
{
|
2023-01-02 22:07:37 +00:00
|
|
|
zfs list -t snapshot $dataset | tail -n1 | cut -d'@' -f2 | cut -d' ' -f 1
|
2022-11-19 08:34:22 +00:00
|
|
|
}
|
|
|
|
|
2023-01-02 22:07:37 +00:00
|
|
|
get_latest_remote_snapshot()
|
2022-11-19 08:34:22 +00:00
|
|
|
{
|
2023-01-02 22:07:37 +00:00
|
|
|
ssh -i ~/.ssh/id_rsa -o port=$ssh_port $user@$addr \
|
|
|
|
"zfs list -t snapshot $zroot/$dataset |
|
|
|
|
tail -n1|cut -d'@' -f2|cut -d' ' -f 1"
|
2022-11-19 08:34:22 +00:00
|
|
|
}
|
|
|
|
|
2023-01-02 22:07:37 +00:00
|
|
|
zfs_allow_origin()
|
2022-11-19 08:34:22 +00:00
|
|
|
{
|
2023-01-02 22:07:37 +00:00
|
|
|
for dataset in $GRAPH_DATASETS; do
|
|
|
|
if [ $BG_TEST_MODE = "TRUE" ]; then
|
|
|
|
echo zfs allow -u $LOCAL_USER $ORIGIN_PERMS $dataset
|
|
|
|
else
|
|
|
|
zfs allow -u $LOCAL_USER $ORIGIN_PERMS $dataset
|
|
|
|
fi
|
|
|
|
done
|
2022-11-19 08:34:22 +00:00
|
|
|
}
|
|
|
|
|
2023-01-02 22:07:37 +00:00
|
|
|
zfs_allow_mirrors()
|
2022-11-19 08:34:22 +00:00
|
|
|
{
|
2023-01-02 22:07:37 +00:00
|
|
|
while read addr user ssh_port zroot; do
|
|
|
|
echo "=== $user@$addr $zroot ==="
|
|
|
|
if [ $BG_TEST_MODE = "TRUE" ]; then
|
|
|
|
echo ssh -i ~/.ssh/id_rsa -o port=$ssh_port $user@$addr \
|
|
|
|
"for dataset in $GRAPH_DATASETS; do
|
|
|
|
zfs allow -u $user $MIRROR_PERMS $zroot/\$dataset
|
|
|
|
done"
|
|
|
|
else
|
|
|
|
ssh -i ~/.ssh/id_rsa -o port=$ssh_port $user@$addr \
|
|
|
|
"for dataset in $GRAPH_DATASETS; do
|
|
|
|
zfs allow -u $user $MIRROR_PERMS $zroot/\$dataset
|
|
|
|
done"
|
|
|
|
fi
|
|
|
|
done < sendnodes.tmp
|
2022-11-19 08:34:22 +00:00
|
|
|
}
|
|
|
|
|
2023-01-02 22:07:37 +00:00
|
|
|
create_snapshots()
|
2022-11-19 08:34:22 +00:00
|
|
|
{
|
2023-01-02 22:07:37 +00:00
|
|
|
snapshot_id="`date -I`-`date +%s`-$LOCAL_TZ"
|
|
|
|
for dataset in $GRAPH_DATASETS; do
|
2022-11-21 02:51:03 +00:00
|
|
|
if [ $BG_TEST_MODE = "TRUE" ]; then
|
2023-01-02 22:07:37 +00:00
|
|
|
echo zfs snapshot $ZFS_SNAPSHOT_OPTS $dataset@$snapshot_id
|
|
|
|
else
|
|
|
|
zfs snapshot $ZFS_SNAPSHOT_OPTS $dataset@$snapshot_id
|
2022-11-20 08:33:44 +00:00
|
|
|
fi
|
2023-01-02 22:07:37 +00:00
|
|
|
done
|
|
|
|
}
|
|
|
|
|
|
|
|
send_latest()
|
|
|
|
{
|
|
|
|
while read addr user ssh_port zroot; do
|
|
|
|
echo "=== $user@$addr $zroot ==="
|
|
|
|
for dataset in $GRAPH_DATASETS; do
|
|
|
|
origin_snapshot=`get_latest_snapshot $dataset`
|
|
|
|
if [ $BG_TEST_MODE = "TRUE" ]; then
|
|
|
|
echo zfs send $ZFS_SEND_OPTS $dataset@$origin_snapshot \| \
|
|
|
|
ssh -i ~/.ssh/id_rsa -o port=$ssh_port $user@$addr \
|
|
|
|
zfs recv $ZFS_RECV_OPTS $zroot/$dataset
|
|
|
|
else
|
|
|
|
zfs send $ZFS_SEND_OPTS $dataset@$origin_snapshot |
|
|
|
|
ssh -i ~/.ssh/id_rsa -o port=$ssh_port \
|
|
|
|
$user@$addr \
|
|
|
|
zfs recv $ZFS_RECV_OPTS $zroot/$dataset
|
|
|
|
fi
|
|
|
|
done
|
2022-11-20 08:33:44 +00:00
|
|
|
done < sendnodes.tmp
|
2022-11-19 08:34:22 +00:00
|
|
|
}
|
|
|
|
|
2023-01-02 22:07:37 +00:00
|
|
|
send_increment()
|
2022-11-19 08:34:22 +00:00
|
|
|
{
|
2023-01-02 22:07:37 +00:00
|
|
|
while read addr user ssh_port zroot; do
|
|
|
|
echo "=== $user@$addr $zroot ==="
|
|
|
|
for dataset in $GRAPH_DATASETS; do
|
|
|
|
origin_snapshot=`get_latest_snapshot`
|
|
|
|
remote_snapshot=`get_latest_remote_snapshot`
|
|
|
|
if [ $BG_TEST_MODE = "TRUE" ]; then
|
|
|
|
echo zfs send $ZFS_SEND_OPTS \
|
|
|
|
-i $dataset@$remote_snapshot \
|
|
|
|
$dataset@$origin_snapshot \| \
|
|
|
|
ssh -i ~/.ssh/id_rsa -o port=$ssh_port $user@$addr \
|
|
|
|
zfs recv $ZFS_RECV_OPTS $zroot/$dataset
|
|
|
|
else
|
|
|
|
zfs send $ZFS_SEND_OPTS \
|
|
|
|
-i $dataset@$remote_snapshot \
|
|
|
|
$dataset@$origin_snapshot |
|
|
|
|
ssh -i ~/.ssh/id_rsa -o port=$ssh_port $user@$addr \
|
|
|
|
zfs recv $ZFS_RECV_OPTS $zroot/$dataset
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
done < sendnodes.tmp
|
2022-11-19 08:34:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-11-20 08:33:44 +00:00
|
|
|
################################### MAIN ####################################
|
|
|
|
|
|
|
|
### Options
|
|
|
|
set -- `getopt "tl:" "$@"` || {
|
|
|
|
echo "Usage: `basename $0` [-tl] [command]" 1>&2
|
|
|
|
exit 1
|
|
|
|
}
|
2022-11-21 02:51:03 +00:00
|
|
|
BG_TEST_MODE=FALSE
|
2022-11-20 08:33:44 +00:00
|
|
|
while :; do
|
|
|
|
case "$1" in
|
|
|
|
-t)
|
2022-11-21 02:51:03 +00:00
|
|
|
BG_TEST_MODE=TRUE
|
2022-11-20 08:33:44 +00:00
|
|
|
echo Test mode.
|
|
|
|
;;
|
|
|
|
--) shift; break ;;
|
|
|
|
esac
|
|
|
|
shift
|
|
|
|
done
|
|
|
|
|
2023-01-02 22:07:37 +00:00
|
|
|
tail -n +2 $nodes_file|grep -v '^#' > sendnodes.tmp
|
2022-11-20 08:33:44 +00:00
|
|
|
|
|
|
|
### Command
|
|
|
|
case "$1" in
|
2023-01-02 22:07:37 +00:00
|
|
|
list) list_datasets ;;
|
|
|
|
list-remote) list_remote_datasets ;;
|
|
|
|
snapshot) create_snapshots ;;
|
|
|
|
configure-mirrors) zfs_allow_mirrors ;;
|
|
|
|
configure-origin) zfs_allow_origin ;;
|
|
|
|
mirror-reset) send_latest ;;
|
|
|
|
mirror-increment) send_increment ;;
|
|
|
|
#mirror-prune) send_increment_with_F ;;
|
2022-11-20 08:33:44 +00:00
|
|
|
esac
|
2023-01-02 22:07:37 +00:00
|
|
|
|
|
|
|
rm sendnodes.tmp
|