Newer
Older
#!/bin/bash
# To move a machine onto a new ZFS
# Load some settings
. /etc/default/zfs-backup
# To move a machine from one zpool to another
function dosql_local() {
SQL="$1"
psql -q -A -t -c "$SQL"
}
function dosql_remote() {
SQL="$1"
cat <<EOF | ssh -A root@$NEW_SERVER sudo -u postgres psql -q -A backups -t
$SQL
EOF
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
}
function cmd_remote() {
CMD="$1"
ssh root@$NEW_SERVER $CMD
}
function create_host_record() {
FQDN=$1
# NB we start with offline=t,disabled=t whilst we migrate the backup.
HOSTID=`dosql_remote "
insert into host (hostname, offline, disabled) values ('$FQDN',true,true);
select host_id from host where hostname='$FQDN';"`
echo $HOSTID
}
function backuptask() {
HOSTID=$1
TASKNAME="$2"
TARGET=$3
SOURCEDIR=$4
SOFT=$5
HARD=$5
if [ -z "$SOFT" ]; then
SOFT=14400
fi
if [ -z "$HARD" ]; then
HARD=86400
fi
BTID=`dosql_remote "
insert into backup_task(host_id,backup_task_name,timeout_soft,timeout_hard,zfs_target,backup_type_id) values
($HOSTID,'$TASKNAME',$SOFT,$HARD,'$TARGET',3);
insert into zfs_rsync_detail (backup_task_id,directory_source) values
((select backup_task_id from backup_task where zfs_target='$TARGET' and host_id=$HOSTID),'$SOURCEDIR');
select backup_task_id from backup_task natural join host natural join zfs_rsync_detail where hostname='$FQDN' and directory_source='$SOURCEDIR' and backup_type_id=3;"`
echo $BTID
}
function configure_pruning() {
CURRENT_TASK_ID=$1
NEW_TASK_ID=$2
PRUNING_IDS=$(dosql_local "select zfs_pruning_id from zfs_pruning where backup_task_id=$CURRENT_TASK_ID")
for PRUNING_ID in $PRUNING_IDS; do
PRUNING_AGE=$(dosql_local "select zfs_pruning_age from zfs_pruning where zfs_pruning_id=$PRUNING_ID")
PRUNING_COUNT=$(dosql_local "select zfs_pruning_count from zfs_pruning where zfs_pruning_id=$PRUNING_ID")
FLAGNAME=$(dosql_local "select flagname from zfs_pruning where zfs_pruning_id=$PRUNING_ID")
dosql_remote "insert into zfs_pruning (backup_task_id, zfs_pruning_age,zfs_pruning_count,flagname) values
($NEW_TASK_ID, $PRUNING_AGE, $PRUNING_COUNT, '$FLAGNAME')"
done
}
if [ $# -lt 2 ] ; then
echo Usage: $0 backup_target_fqdn new_backup_server [zpool_name]
echo Moves the named machine to a new server
exit 1
fi
HN=$1
# Find FQDN for $HN
FQDN=`getent hosts $HN | awk ' { print $2 } '`
NEW_SERVER=$2
ZPOOL_TARGET=$3
# Which zfs is it already on?
echo Finding source ZFS for $FQDN
SOURCES=`zfs list -H -o name | grep -v zroot | grep /$FQDN$ | sed "sZ/'$FQDN$'ZZ" | wc -l `
#echo Found $SOURCES possibilities
if [ $SOURCES != 1 ] ;then
echo Found more than one possible ZFS for $HN
exit 2
fi
if ! grep -q ^$NEW_SERVER: $PGPASSFILE ; then
echo $NEW_SERVER not found in $PGPASSFILE \(use fqdn?\)
exit 5
fi
SOURCE=`zfs list -H -o name | grep -v zroot | grep /$FQDN$ | sed "sZ/$FQDN\\$ZZ"`
# Which target is it?
if [ -z "$ZPOOL_TARGET" ] ; then
echo Finding a target ZFS automatically
ZPOOL=$(cmd_remote "zfs list -H -oname -S avail -d0 | grep -v zroot | head -n1")
ZPOOL_TARGET=$ZPOOL
fi
if ! ssh root@$NEW_SERVER zpool list $ZPOOL_TARGET &>/dev/null ; then
echo $ZPOOL_TARGET does not exist on $NEW_SERVER
exit 3
fi
echo moving $FQDN from $SOURCE to $ZPOOL_TARGET on $NEW_SERVER
set -e
RUNNING=`dosql_local "select count(*) from backup_log natural join backup_task natural join host where hostname='$FQDN' and ended_processing is null and started_processing is not null"`
RUNNING=`echo $RUNNING` # chomp
#echo RUNNING $RUNNING
if ! [ "$RUNNING" = 0 ] ; then
echo $FQDN has a job running
exit 3
fi
# Disable this host locally
dosql_local "update host set disabled='t' where hostname='$FQDN';"
# De-queue jobs for this host
dosql_local "delete from backup_log where backup_task_id in (select backup_task_id from backup_task natural join host where hostname='$FQDN') and ended_processing is null and started_processing is null;"
# Move ZFS
NOW=$(date +%s)
zfs snapshot -r $SOURCE/$FQDN@$NOW
zfs hold zfs-moving $SOURCE/$FQDN@$NOW
SIZE=`zfs list -H -o used $SOURCE/$FQDN`
echo Sending ZFS [ $SIZE]
zfs send -R $SOURCE/$FQDN@$NOW | mbuffer | ssh root@$NEW_SERVER zfs receive $ZPOOL_TARGET/$FQDN
CURRENT_HOST_ID=$(dosql_local "select host_id from host where hostname='$FQDN'")
NEW_HOST_ID=$(create_host_record $FQDN)
# get current tasks
TASK_IDS=$(dosql_local "select backup_task_id from backup_task where host_id='$CURRENT_HOST_ID'")
# create new tasks
for TASK_ID in $TASK_IDS; do
echo got task $TASK_ID
SOURCEDIR=$(dosql_local "select directory_source from zfs_rsync_detail where backup_task_id='$TASK_ID'")
SOFT=$(dosql_local "select timeout_soft from backup_task where backup_task_id='$TASK_ID'")
HARD=$(dosql_local "select timeout_hard from backup_task where backup_task_id='$TASK_ID'")
TASKNAME=$(dosql_local "select backup_task_name from backup_task where backup_task_id='$TASK_ID'")
CURRENT_ZFS_TARGET=$(dosql_local "select zfs_target from backup_task where backup_task_id='$TASK_ID'")
NEW_ZFS_TARGET=${ZPOOL_TARGET}/$(echo $CURRENT_ZFS_TARGET | cut -d '/' -f 2-)
NEW_TASK_ID=$(backuptask $NEW_HOST_ID "$TASKNAME" $NEW_ZFS_TARGET $SOURCEDIR $SOFT $HARD)
configure_pruning $TASK_ID $NEW_TASK_ID
scp /etc/chem-zfs-backup-server/zfs-rsync.d/${FQDN}_${SOURCEDIR//\//.} $NEW_SERVER:/etc/chem-zfs-backup-server/zfs-rsync.d
rsync -av /etc/chem-zfs-backup-server/zfs-rsync.d/${FQDN} $NEW_SERVER:/etc/chem-zfs-backup-server/zfs-rsync.d
done
dosql_remote "update host set disabled='f',offline='f' where host_id=$NEW_HOST_ID"