New ftpsync upstream.
[mirror-admin] / bin / runmirrors
CommitLineData
57ab47fa
MW
1#! /bin/bash
2
3set -e
4set -u
5
6# runmirrors script for Debian
7# Based losely on existing scripts, written by an unknown number of
8# different people over the years.
9#
10# Copyright (C) 2008, 2009 Joerg Jaspert <joerg@debian.org>
11#
12# This program is free software; you can redistribute it and/or
13# modify it under the terms of the GNU General Public License as
14# published by the Free Software Foundation; version 2.
15#
16# This program is distributed in the hope that it will be useful, but
17# WITHOUT ANY WARRANTY; without even the implied warranty of
18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19# General Public License for more details.
20#
21# You should have received a copy of the GNU General Public License
22# along with this program; if not, write to the Free Software
23# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24
25# In case the admin somehow wants to have this script located someplace else,
26# he can set BASEDIR, and we will take that. If it is unset we take ${HOME}
27BASEDIR=${BASEDIR:-"${HOME}"}
28
29NAME="$(basename $0)"
30
31HELP="$0, (C) 2008, 2009 by Joerg Jaspert <joerg@debian.org>\n
32Usage:\n\n
33
341.) a single parameter with NO leading -.\n
35\t This will will then be used as the addition for our configfile. Ie. \`$0 security\` will\n
36\t have us look for ${NAME}-security.{conf,mirror} files.\n\n
37
382.) using getopt style parameters:\n
39\t -a [NAME] - Same as 1.) above, used for the config files. Default empty.\n
40\t -k [TYPE] - Type of push. all, stage2, mhop. Default mhop.\n
41\t -f - Run from within the mirrorscript ftpsync. Don't use from commandline!\n
42\t -h - Print this help and exit
43"
44# If we got options, lets see if we use newstyle options, or oldstyle. If oldstyle
45# it will not start with a -. If we find oldstyle we assume its only one, the config
46# name we run on.
47if [ $# -gt 0 ]; then
48 if [ "x${1:0:1}x" != "x-x" ]; then
49 # Yes, does not start with a -, so use it for the config name.
50 CONF=${1:-""}
51 if [ -n "${CONF}" ]; then
52 NAME="${NAME}-${CONF}"
53 fi
54 else
55 # Yeah well, new style, starting with - for getopts
56 while getopts ':a:k:fh' OPTION ; do
57 case $OPTION in
58 a) CONF="${OPTARG}"
59 if [ -n "${CONF}" ]; then
60 NAME="${NAME}-${CONF}"
61 fi
62 ;;
63 k) PUSHKIND="${OPTARG}"
64 ;;
65 f) FROMFTPSYNC="true"
66 ;;
67 h) echo -e $HELP
68 exit 0
69 ;;
70
71 *) echo "Invalid usage"
72 echo -e $HELP
73 exit 1
74 ;;
75 esac
76 done
77 fi
78fi
79# Make sure the values are always defined, even if there was no commandline option
80# for them
81# Default config is empty
82CONF=${CONF:-""}
83
84# Set the default to all, if we didnt get told about it. Currently
85# valid: all - normal push. mhop - multi-hop multi-stage push, this is stage1,
86# stage2 - staged push, second phase. Default is mhop.
87PUSHKIND=${PUSHKIND:-"mhop"}
88
89# If we are pushed from within ftpsync. Default false.
90FROMFTPSYNC=${FROMFTPSYNC:-"false"}
91
92########################################################################
93# Read our config file
94. "${BASEDIR}/etc/${NAME}.conf"
95
96# Source our common functions
97. "${BASEDIR}/etc/common"
98
99# Set sane defaults if the configfile didn't do that for us.
100# The directory for our logfiles
101LOGDIR=${LOGDIR:-"${BASEDIR}/log"}
102# Our own logfile
103LOG=${LOG:-"${LOGDIR}/${NAME}.log"}
104# Our lockfile directory
105LOCKDIR=${LOCKDIR:-"${BASEDIR}/locks"}
106# How many logfiles to keep
107LOGROTATE=${LOGROTATE:-14}
108# Our mirrorfile
109MIRRORS=${MIRRORS:-"${BASEDIR}/etc/${NAME}.mirror"}
110# used by log()
111PROGRAM=${PROGRAM:-"${NAME}-$(hostname -s)"}
112# extra ssh options we might want hostwide
113SSH_OPTS=${SSH_OPTS:-"-o StrictHostKeyChecking=no"}
114# Whats our archive name? We will also tell our leafs about it
115PUSHARCHIVE=${PUSHARCHIVE:-"${CONF}"}
116# How long to wait for mirrors to do stage1 if we have multi-stage syncing
117PUSHDELAY=${PUSHDELAY:-600}
118# Which ssh key to use?
119KEYFILE=${KEYFILE:-".ssh/pushmirror"}
120# where to send mails to
121if [ "x$(hostname -d)x" != "xdebian.orgx" ]; then
122 # We are not on a debian.org host
123 MAILTO=${MAILTO:-"root"}
124else
125 # Yay, on a .debian.org host
126 MAILTO=${MAILTO:-"mirrorlogs@debian.org"}
127fi
128
129if ! [ -f "${BASEDIR}/${KEYFILE}" ]; then
130 error "SSH Key ${BASEDIR}/${KEYFILE} does not exist" >> "${LOG}"
131 exit 5
132fi
133
134# Hooks
135HOOK1=${HOOK1:-""}
136HOOK2=${HOOK2:-""}
137HOOK3=${HOOK3:-""}
138
139########################################################################
140
141# Some sane defaults
142cd "${BASEDIR}"
143umask 022
144
145# Make sure we have our log and lock directories
146mkdir -p "${LOGDIR}"
147mkdir -p "${LOCKDIR}"
148
149trap 'log "Mirrorpush done" >> "${LOG}"; savelog "${LOG}" > /dev/null' EXIT
150
151log "Pushing leaf mirrors. Inside ftpsync: ${FROMFTPSYNC}. Pushkind: ${PUSHKIND}" >> "${LOG}"
152
153HOOK=(
154 HOOKNR=1
155 HOOKSCR=${HOOK1}
156)
157hook $HOOK
158
159# From here on we do *NOT* want to exit on errors. We don't want to
160# stop pushing mirrors just because we can't reach one of them.
161set +e
162
163# Built up our list of 2-stage mirrors.
164PUSHLOCKS=""
165PUSHLOCKS=$(get2stage)
166
167# In case we have it - remove. It is used to synchronize multi-stage mirroring
168rm -f "${LOCKDIR}/all_stage1"
169
170# Now read our mirrorfile and push the mirrors defined in there.
171# We use grep to easily sort out all lines having a # in front of them or are empty.
172egrep -v '^[[:space:]]*(#|$)' "${MIRRORS}" |
173while read MTYPE MLNAME MHOSTNAME MUSER MSSHOPT; do
174 if [ "x${MTYPE}x" = "xDELAYx" ]; then
175 # We should wait a bit.
176 if [ -z ${MLNAME} ]; then
177 MLNAME=600
178 fi
179 log "Delay of ${MLNAME} requested, sleeping" >> "${LOG}"
180 sleep ${MLNAME}
181 continue
182 fi
183
184 # If we are told we have a mhop sync to do and are called from within ftpsync,
185 # we will only look at staged/mhop entries and ignore the rest.
186 if [ "x${PUSHKIND}x" = "xmhopx" ] && [ "x${FROMFTPSYNC}x" = "xtruex" ]; then
187 if [ "x${MTYPE}x" != "xstagedx" ] && [ "x${MTYPE}x" != "xmhopx" ]; then
188 continue
189 fi
190 fi
191
192 # Now, MSSHOPT may start with a -. In that case the whole rest of the line is taken
193 # as a set of options to give to ssh, we pass it without doing anything with it.
194 # If it starts with a 1 or 2 then it will tell us about the ssh protocol version to use,
195 # and also means we look if there is one value more after a space. That value would then
196 # be the ssh keyfile we use with -i. That gives us full flexibility for all
197 # ssh options but doesn't destroy backwards compatibility.
198 # If it is empty we assume proto 2 and the default keyfile.
199 #
200 # There is one bug in here. We will give out the master keyfile, even if there is a
201 # "-i /bla/bla" in the options. ssh stuffs them together and presents two keys to the
202 # target server. In the case both keys do some actions- the first one presented wins.
203 # And this might not be what one wants.
204 #
205 # The only sane way to go around this, i think, is by dropping backward compability.
206 # Which I don't really like.
207 if [ -n "${MSSHOPT}" ]; then
208 # So its not empty, lets check if it starts with a - and as such is a "new-style"
209 # ssh options set.
210 if [ "x${MSSHOPT:0:1}x" = "x-x" ]; then
211 # Yes we start with a -
212 SSHOPT="${MSSHOPT}"
213 MPROTO="99"
214 MKEYFILE="${BASEDIR}/${KEYFILE}"
215 elif [ ${MSSHOPT:0:1} -eq 1 ] || [ ${MSSHOPT:0:1} -eq 2 ]; then
216 # We do seem to have oldstyle options here.
217 MPROTO=${MSSHOPT:0:1}
2e267ae8 218 MKEYFILE=${MSSHOPT:2}
57ab47fa
MW
219 SSHOPT=""
220 else
221 error "I don't know what is configured for mirror ${MLNAME}"
222 continue
223 fi
224 else
225 MPROTO=2
226 MKEYFILE="${BASEDIR}/${KEYFILE}"
227 SSHOPT=""
228 fi
229
230 # Built our array
231 SIGNAL_OPTS=(
232 MIRROR="${MLNAME}"
233 HOSTNAME="${MHOSTNAME}"
234 USERNAME="${MUSER}"
235 SSHPROTO="${MPROTO}"
236 SSHKEY="${MKEYFILE}"
237 SSHOPTS="${SSHOPT/ /#}"
238 PUSHLOCKOWN="${LOCKDIR}/${MLNAME}.stage1"
239 PUSHTYPE="${MTYPE}"
240 PUSHARCHIVE=${PUSHARCHIVE}
241 PUSHKIND=${PUSHKIND}
242 FROMFTPSYNC=${FROMFTPSYNC}
243 )
244
245 # And finally, push the mirror
246 log "Trigger ${MLNAME}" >> "${LOG}"
247 signal "${SIGNAL_OPTS}" &
248 log "Trigger for ${MLNAME} done" >> "${LOG}"
249
250 HOOK=(
251 HOOKNR=2
252 HOOKSCR=${HOOK2}
253 )
254 hook $HOOK
255 set +e
256done
257
258# If we are run from within ftpsync *and* have an mhop push to send on, we have
259# to wait until the push is gone through and they all returned, or we will exit
260# much too early.
261# As the signal routine touches $LOCKDIR/all_stage1 when all are done, its
262# easy enough just to wait for that to appear. Of course we do the same game
263# with PUSHDELAY to not wait forever.
264if [ "xtruex" = "x${FROMFTPSYNC}x" ] && [ "xmhopx" = "x${PUSHKIND}x" ]; then
265 tries=0
266 # We do not wait forever
267 while [ ${tries} -lt ${PUSHDELAY} ]; do
268 if [ -f "${LOCKDIR}/all_stage1" ]; then
269 break
270 fi
271 tries=$((tries + 5))
272 sleep 5
273 done
274
275 if [ ${tries} -ge ${PUSHDELAY} ]; then
276 error "Failed to wait for our mirrors when sending mhop push down." >> "${LOG}"
277 fi
278fi
279
280HOOK=(
281 HOOKNR=3
282 HOOKSCR=${HOOK3}
283)
284hook $HOOK
285
286exit 0