2 # No way I try to deal with a crippled sh just for POSIX foo.
4 # Copyright (C) 2009 Joerg Jaspert <joerg@debian.org>
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License as
8 # published by the Free Software Foundation; version 2.
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 # Homer: Are you saying you're never going to eat any animal again? What
25 # Lisa: Dad, those all come from the same animal.
26 # Homer: Heh heh heh. Ooh, yeah, right, Lisa. A wonderful, magical animal.
30 # make sure to only use defined variables
32 # ERR traps should be inherited from functions too. (And command
33 # substitutions and subshells and whatnot, but for us the functions is
34 # the important part here)
37 # import the general variable set.
38 export SCRIPTVARS=/srv/ftp.debian.org/dak/config/debian/vars
41 ########################################################################
43 ########################################################################
44 # common functions are "outsourced"
45 . "${configdir}/common"
47 # Timestamp. Used for dinstall stat graphs
49 echo "Archive maintenance timestamp ($1): $(date +%H:%M:%S)"
55 rm -f ${LOCK_ACCEPTED}
58 # If we error out this one is called, *FOLLOWED* by cleanup above
60 ERRDATE=$(date "+%Y.%m.%d-%H:%M:%S")
63 subject="ATTENTION ATTENTION!"
64 if [ "${error}" = "false" ]; then
65 subject="${subject} (continued)"
67 subject="${subject} (interrupted)"
69 subject="${subject} dinstall error at ${ERRDATE} in ${STAGEFILE} - (Be quiet, Brain, or I'll stab you with a Q-tip)"
71 cat "${STAGEFILE}.log" | mail -s "${subject}" -a "X-Debian: DAK" cron@ftp-master.debian.org
74 ########################################################################
75 # the actual dinstall functions follow #
76 ########################################################################
78 # Setup the notice file to tell bad mirrors they used the wrong time
82 Packages are currently being installed and indices rebuilt.
83 Maintenance is automatic, starting at 01|07|13|19:52 UTC,
84 and ending about an hour later. This file is then removed.
86 You should not mirror the archive during this period. If you find this
87 file on a Debian mirror please have a nice talk with the admin. They
88 are doing something wrong.
92 # pushing merkels QA user, part one
94 log "Telling merkels QA user that we start dinstall"
95 ssh -2 -i ~dak/.ssh/push_merkel_qa -o BatchMode=yes -o SetupTimeOut=90 -o ConnectTimeout=90 qa@merkel.debian.org sleep 1
98 # Create the postgres dump files
99 function pgdump_pre() {
100 log "Creating pre-daily-cron-job backup of projectb database..."
101 pg_dump projectb > $base/backup/dump_pre_$(date +%Y.%m.%d-%H:%M:%S)
104 function pgdump_post() {
105 log "Creating post-daily-cron-job backup of projectb database..."
107 POSTDUMP=$(date +%Y.%m.%d-%H:%M:%S)
108 pg_dump projectb > $base/backup/dump_$POSTDUMP
109 pg_dumpall --globals-only > $base/backup/dumpall_$POSTDUMP
110 ln -sf $base/backup/dump_$POSTDUMP current
111 ln -sf $base/backup/dumpall_$POSTDUMP currentall
114 # Load the dak-dev projectb
115 function pgdakdev() {
117 echo "drop database projectb" | psql -p 5433 template1
118 cat currentall | psql -p 5433 template1
119 createdb -p 5433 -T template0 projectb
120 fgrep -v '\connect' current | psql -p 5433 projectb
123 # Updating various files
125 log "Updating Bugs docu, Mirror list and mailing-lists.txt"
127 $scriptsdir/update-bugdoctxt
128 $scriptsdir/update-mirrorlists
129 $scriptsdir/update-mailingliststxt
130 $scriptsdir/update-pseudopackages.sh
133 # Process (oldstable)-proposed-updates "NEW" queue
134 function punew_do() {
135 cd "${queuedir}/${1}"
137 dak process-new -a -C COMMENTS >> REPORT || true
141 log "Doing automated p-u-new processing"
145 log "Doing automated o-p-u-new processing"
149 # The first i18n one, syncing new descriptions
151 log "Synchronizing i18n package descriptions"
152 # First sync their newest data
153 cd ${scriptdir}/i18nsync
154 rsync -aq --delete --delete-after ddtp-sync:/does/not/matter . || true
156 # Now check if we still know about the packages for which they created the files
157 # is the timestamp signed by us?
158 if $(gpgv --keyring /srv/ftp.debian.org/s3kr1t/dot-gnupg/pubring.gpg timestamp.gpg timestamp); then
159 # now read it. As its signed by us we are sure the content is what we expect, no need
160 # to do more here. And we only test -d a directory on it anyway.
161 TSTAMP=$(cat timestamp)
162 # do we have the dir still?
163 if [ -d ${scriptdir}/i18n/${TSTAMP} ]; then
165 if ${scriptsdir}/ddtp-i18n-check.sh . ${scriptdir}/i18n/${TSTAMP}; then
166 # Yay, worked, lets copy around
167 for dir in squeeze sid; do
168 if [ -d dists/${dir}/ ]; then
169 cd dists/${dir}/main/i18n
170 rsync -aq --delete --delete-after . ${ftpdir}/dists/${dir}/main/i18n/.
172 cd ${scriptdir}/i18nsync
175 echo "ARRRR, bad guys, wrong files, ARRR"
176 echo "Arf, Arf, Arf, bad guys, wrong files, arf, arf, arf" | mail -s "Don't you kids take anything. I'm watching you. I've got eye implants in the back of my head." debian-l10n-devel@lists.alioth.debian.org
179 echo "ARRRR, missing the timestamp ${TSTAMP} directory, not updating i18n, ARRR"
180 echo "Arf, Arf, Arf, missing the timestamp ${TSTAMP} directory, not updating i18n, arf, arf, arf" | mail -s "Lisa, if you don't like your job you don't strike. You just go in every day and do it really half-assed. That's the American way." debian-l10n-devel@lists.alioth.debian.org
183 echo "ARRRRRRR, could not verify our timestamp signature, ARRR. Don't mess with our files, i18n guys, ARRRRR."
184 echo "Arf, Arf, Arf, could not verify our timestamp signature, arf. Don't mess with our files, i18n guys, arf, arf, arf" | mail -s "You can't keep blaming yourself. Just blame yourself once, and move on." debian-l10n-devel@lists.alioth.debian.org
188 # Process the accepted queue
189 function accepted() {
190 log "Processing queue/accepted"
191 rm -f "$accepted/REPORT"
192 dak process-accepted -pa -d "$accepted" > "$accepted/REPORT"
193 cat "$accepted/REPORT" | mail -s "Install for $(date +"%D - %R")" ftpmaster@ftp-master.debian.org
194 chgrp debadmin "$accepted/REPORT"
195 chmod 664 "$accepted/REPORT"
199 log "Checking for cruft in overrides"
202 log "Fixing symlinks in $ftpdir"
203 symlinks -d -r $ftpdir
207 log "Generating suite file lists for apt-ftparchive"
208 dak make-suite-file-list
211 function fingerprints() {
212 log "Updating fingerprints"
213 dak import-keyring -L /srv/keyring.debian.org/keyrings/debian-keyring.gpg
216 function overrides() {
217 log "Writing overrides into text files"
222 rm -f override.sid.all3
223 for i in main contrib non-free main.debian-installer; do cat override.sid.$i >> override.sid.all3; done
227 log "Generating package / file mapping"
228 dak make-pkg-file-mapping | bzip2 -9 > $base/ftp/indices/package-file.map.bz2
231 function packages() {
232 log "Generating Packages and Sources files"
234 apt-ftparchive generate apt.conf
238 log "Generating pdiff files"
239 dak generate-index-diffs
243 log "Generating Release files"
244 dak generate-releases
247 function dakcleanup() {
248 log "Cleanup old packages/files"
249 dak clean-suites -m 10000
254 # Needs to be rebuilt, as files have moved. Due to unaccepts, we need to
255 # update this before wanna-build is updated.
256 log "Regenerating wanna-build/buildd information"
257 psql projectb -A -t -q -c "SELECT filename FROM queue_build WHERE suite = 5 AND queue = 0 AND in_queue = true AND filename ~ 'd(sc|eb)$'" > $dbdir/dists/unstable_accepted.list
258 symlinks -d /srv/incoming.debian.org/buildd > /dev/null
259 apt-ftparchive generate apt.conf.buildd
262 function buildd_dir() {
263 # Rebuilt the buildd dir to avoid long times of 403
264 log "Regenerating the buildd incoming dir"
265 STAMP=$(date "+%Y%m%d%H%M")
270 log "Running various scripts from $scriptsdir"
280 echo "Regenerating \"public\" mirror/ hardlink fun"
282 rsync -aH --link-dest ${ftpdir} --exclude Archive_Maintenance_In_Progress --delete --delete-after --ignore-errors ${ftpdir}/. .
286 log "Trigger daily wanna-build run"
287 ssh -o BatchMode=yes -o SetupTimeOut=90 -o ConnectTimeout=90 wbadm@buildd /org/wanna-build/trigger.daily || echo "W-B trigger.daily failed" | mail -s "W-B Daily trigger failed" ftpmaster@ftp-master.debian.org
291 log "Expiring old database dumps..."
293 $scriptsdir/expire_dumps -d . -p -f "dump_*"
296 function transitionsclean() {
297 log "Removing out of date transitions..."
299 dak transitions -c -a
303 # Send a report on NEW/BYHAND packages
304 log "Nagging ftpteam about NEW/BYHAND packages"
305 dak queue-report | mail -e -s "NEW and BYHAND on $(date +%D)" ftpmaster@ftp-master.debian.org
306 # and one on crufty packages
307 log "Sending information about crufty packages"
308 dak cruft-report > $webdir/cruft-report-daily.txt
309 dak cruft-report -s experimental >> $webdir/cruft-report-daily.txt
310 cat $webdir/cruft-report-daily.txt | mail -e -s "Debian archive cruft report for $(date +%D)" ftpmaster@ftp-master.debian.org
314 log "Updating DM html page"
315 $scriptsdir/dm-monitor >$webdir/dm-uploaders.html
319 log "Categorizing uncategorized bugs filed against ftp.debian.org"
324 # Push dak@merkel so it syncs the projectb there. Returns immediately, the sync runs detached
325 log "Trigger merkel/flotows projectb sync"
326 ssh -2 -o BatchMode=yes -o SetupTimeOut=30 -o ConnectTimeout=30 -i ~/.ssh/push_merkel_projectb dak@merkel.debian.org sleep 1
327 # Also trigger flotow, the ftpmaster test box
328 ssh -2 -o BatchMode=yes -o SetupTimeOut=30 -o ConnectTimeout=30 -i ~/.ssh/push_flotow_projectb dak@flotow.debconf.org sleep 1
332 # Push dak@merkel to tell it to sync the dd accessible parts. Returns immediately, the sync runs detached
333 log "Trigger merkels dd accessible parts sync"
334 ssh -2 -o BatchMode=yes -o SetupTimeOut=30 -o ConnectTimeout=30 -i ~/.ssh/push_merkel_ddaccess dak@merkel.debian.org sleep 1
337 function runparts() {
338 log "Using run-parts to run scripts in $base/scripts/distmnt"
339 run-parts --report $base/scripts/distmnt
343 log "Exporting package data foo for i18n project"
344 STAMP=$(date "+%Y%m%d%H%M")
345 mkdir -p ${scriptdir}/i18n/${STAMP}
346 cd ${scriptdir}/i18n/${STAMP}
347 dak control-suite -l stable > lenny
348 dak control-suite -l testing > squeeze
349 dak control-suite -l unstable > sid
350 echo "${STAMP}" > timestamp
351 gpg --secret-keyring /srv/ftp.debian.org/s3kr1t/dot-gnupg/secring.gpg --keyring /srv/ftp.debian.org/s3kr1t/dot-gnupg/pubring.gpg --no-options --batch --no-tty --armour --default-key 55BE302B --detach-sign -o timestamp.gpg timestamp
355 ln -sfT ${scriptdir}/i18n/${STAMP} i18n
358 find ./i18n -mindepth 1 -maxdepth 1 -mtime +2 -not -name "${STAMP}" -type d -print0 | xargs --no-run-if-empty -0 rm -rf
362 log "Updating stats data"
364 $scriptsdir/update-ftpstats $base/log/* > $base/misc/ftpstats.data
365 R --slave --vanilla < $base/misc/ftpstats.R
366 dak stats arch-space > $webdir/arch-space
367 dak stats pkg-nums > $webdir/pkg-nums
370 function aptftpcleanup() {
371 log "Clean up apt-ftparchive's databases"
373 apt-ftparchive -q clean apt.conf
376 function compress() {
377 log "Compress old psql backups"
379 find -maxdepth 1 -mindepth 1 -type f -name 'dump_pre_*' -mtime +2 -print0 | xargs -0 --no-run-if-empty rm
381 find -maxdepth 1 -mindepth 1 -type f -name 'dump_*' \! -name '*.bz2' \! -name '*.gz' -mmin +720 |
382 while read dumpname; do
383 echo "Compressing $dumpname"
384 bzip2 -9fv "$dumpname"
386 find -maxdepth 1 -mindepth 1 -type f -name "dumpall_*" \! -name '*.bz2' \! -name '*.gz' -mmin +720 |
387 while read dumpname; do
388 echo "Compressing $dumpname"
389 bzip2 -9fv "$dumpname"
391 finddup -l -d $base/backup
394 function logstats() {
395 $masterdir/tools/logs.py "$1"
398 # save timestamp when we start
399 function savetimestamp() {
400 NOW=`date "+%Y.%m.%d-%H:%M:%S"`
401 echo ${NOW} > "${dbdir}/dinstallstart"
404 function maillogfile() {
405 cat "$LOGFILE" | mail -s "Log for dinstall run of ${NOW}" cron@ftp-master.debian.org
408 function renamelogfile() {
409 if [ -f "${dbdir}/dinstallstart" ]; then
410 NOW=$(cat "${dbdir}/dinstallstart")
412 mv "$LOGFILE" "$logdir/dinstall_${NOW}.log"
413 logstats "$logdir/dinstall_${NOW}.log"
414 bzip2 -9 "$logdir/dinstall_${NOW}.log"
416 error "Problem, I don't know when dinstall started, unable to do log statistics."
417 NOW=`date "+%Y.%m.%d-%H:%M:%S"`
419 mv "$LOGFILE" "$logdir/dinstall_${NOW}.log"
420 bzip2 -9 "$logdir/dinstall_${NOW}.log"
424 function testingsourcelist() {
425 dak ls -s testing -f heidi -r .| egrep 'source$' > ${webdir}/testing.list
428 # do a last run of process-unchecked before dinstall is on.
429 function process_unchecked() {
430 log "Processing the unchecked queue"
432 UNCHECKED_WITHOUT_LOCK="-p"
437 ########################################################################
438 ########################################################################
440 # Function to save which stage we are in, so we can restart an interrupted
441 # dinstall. Or even run actions in parallel, if we dare to, by simply
442 # backgrounding the call to this function. But that should only really be
443 # done for things we don't care much about.
445 # This should be called with the first argument being an array, with the
447 # - FUNC - the function name to call
448 # - ARGS - Possible arguments to hand to the function. Can be the empty string
449 # - TIME - The timestamp name. Can be the empty string
450 # - ERR - if this is the string false, then the call will be surrounded by
451 # set +e ... set -e calls, so errors in the function do not exit
452 # dinstall. Can be the empty string, meaning true.
454 # MAKE SURE TO KEEP THIS THE LAST FUNCTION, AFTER ALL THE VARIOUS ONES
455 # ADDED FOR DINSTALL FEATURES!
460 STAGEFILE="${stagedir}/${FUNC}"
461 if [ -f "${STAGEFILE}" ]; then
462 stamptime=$(/usr/bin/stat -c %Z "${STAGEFILE}")
464 difference=$(( $unixtime - $stamptime ))
465 if [ ${difference} -ge 14400 ]; then
466 log_error "Did already run ${FUNC}, stagefile exists, but that was ${difference} seconds ago. Please check."
468 log "Did already run ${FUNC}, not calling again..."
473 debug "Now calling function ${FUNC}. Arguments: ${ARGS}. Timestamp: ${TIME}"
475 # Make sure we are always at the same place. If a function wants to be elsewhere,
476 # it has to cd first!
479 # Now redirect the output into $STAGEFILE.log. In case it errors out somewhere our
480 # errorhandler trap can then mail the contents of $STAGEFILE.log only, instead of a whole
481 # dinstall logfile. Short error mails ftw!
482 exec >> "${STAGEFILE}.log" 2>&1
484 if [ -f "${LOCK_STOP}" ]; then
485 log "${LOCK_STOP} exists, exiting immediately"
489 if [ "${ERR}" = "false" ]; then
494 # No matter what happened in the function, we make sure we have set -e default state back
497 # Make sure we are always at the same place.
502 if [ -n "${TIME}" ]; then
506 # And the output goes back to the normal logfile
507 exec >> "$LOGFILE" 2>&1
509 # Now we should make sure that we have a usable dinstall.log, so append the $STAGEFILE.log
511 cat "${STAGEFILE}.log" >> "${LOGFILE}"
512 rm -f "${STAGEFILE}.log"
514 if [ -f "${LOCK_STOP}" ]; then
515 log "${LOCK_STOP} exists, exiting immediately"
520 ########################################################################
523 LOGFILE="$logdir/dinstall.log"
525 exec >> "$LOGFILE" 2>&1
527 # usually we are not using debug logs. Set to 1 if you want them.
533 # where do we want mails to go? For example log entries made with error()
534 if [ "x$(hostname -s)x" != "xriesx" ]; then
535 # Not our ftpmaster host
536 MAILTO=${MAILTO:-"root"}
539 MAILTO=${MAILTO:-"ftpmaster@debian.org"}
542 # How many logfiles to keep
543 LOGROTATE=${LOGROTATE:-400}
545 # Marker for dinstall start
546 DINSTALLSTART="${lockdir}/dinstallstart"
547 # Marker for dinstall end
548 DINSTALLEND="${lockdir}/dinstallend"
550 touch "${DINSTALLSTART}"
553 # Tell everyone we are doing some work
554 NOTICE="$ftpdir/Archive_Maintenance_In_Progress"
556 # lock cron.unchecked (it immediately exits when this exists)
557 LOCK_DAILY="$lockdir/daily.lock"
559 # Lock cron.unchecked from doing work
560 LOCK_ACCEPTED="$lockdir/unchecked.lock"
562 # Lock process-new from doing work
563 LOCK_NEW="$lockdir/processnew.lock"
565 # This file is simply used to indicate to britney whether or not
566 # the Packages file updates completed sucessfully. It's not a lock
567 # from our point of view
568 LOCK_BRITNEY="$lockdir/britney.lock"
570 # If this file exists we exit immediately after the currently running
572 LOCK_STOP="$lockdir/archive.stop"
574 lockfile -l 3600 "${LOCK_DAILY}"
576 trap cleanup EXIT TERM HUP INT QUIT
578 touch "${LOCK_BRITNEY}"
614 TIME="External Updates"
644 lockfile "$LOCK_ACCEPTED"
648 FUNC="process_unchecked"
680 rm -f "$LOCK_ACCEPTED"
685 TIME="make-suite-file-list"
693 TIME="import-keyring"
709 TIME="pkg-file-mapping"
717 TIME="apt-ftparchive"
765 TIME="mirror hardlinks"
780 rm -f "${LOCK_DAILY}"
782 ts "locked part finished"
801 FUNC="transitionsclean"
802 TIME="transitionsclean"
834 TIME="merkel projectb push"
865 FUNC="testingsourcelist"
872 rm -f ${LOCK_BRITNEY}
884 TIME="apt-ftparchive cleanup"
892 TIME="merkel ddaccessible sync"
906 log "Daily cron scripts successful, all done"
908 exec > "$logdir/afterdinstall.log" 2>&1
919 # Now, at the very (successful) end of dinstall, make sure we remove
920 # our stage files, so the next dinstall run will do it all again.
922 touch "${DINSTALLEND}"