]> git.decadent.org.uk Git - dak.git/blob - config/debian/cron.dinstall
7c3880806878c609da809e8149c75ad535fe6bef
[dak.git] / config / debian / cron.dinstall
1 #!/bin/bash
2 # No way I try to deal with a crippled sh just for POSIX foo.
3
4 # Copyright (C) 2009 Joerg Jaspert <joerg@debian.org>
5 #
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.
9 #
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.
14 #
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.
18
19 # exit on errors
20 set -e
21 # make sure to only use defined variables
22 set -u
23
24 # import the general variable set.
25 export SCRIPTVARS=/srv/ftp.debian.org/dak/config/debian/vars
26 . $SCRIPTVARS
27
28 ########################################################################
29 # Functions                                                            #
30 ########################################################################
31 # log something (basically echo it together with a timestamp)
32 #
33 # Set $PROGRAM to a string to have it added to the output.
34 function log () {
35         if [ -z "${PROGRAM}" ]; then
36                 echo "$(date +"%b %d %H:%M:%S") $(hostname -s) [$$] $@"
37         else
38                 echo "$(date +"%b %d %H:%M:%S") $(hostname -s) ${PROGRAM}[$$]: $@"
39         fi
40 }
41
42 # log the message using log() but then also send a mail
43 # to the address configured in MAILTO (if non-empty)
44 function log_error () {
45         log "$@"
46         if [ -z "${MAILTO}" ]; then
47                 echo "$@" | mail -e -s "[$PROGRAM@$(hostname -s)] ERROR [$$]" ${MAILTO}
48         fi
49 }
50
51 # debug log, only output when DEBUG=1
52 function debug () {
53     if [ $DEBUG -eq 1 ]; then
54         log "$*"
55     fi
56 }
57
58 # Timestamp. Used for dinstall stat graphs
59 function ts() {
60         TS=$(($TS+1));
61         echo "Archive maintenance timestamp $TS ($1): $(date +%H:%M:%S)"
62 }
63
64 # Cleanup actions
65 function cleanup() {
66         rm -f ${LOCK_DAILY}
67         rm -f ${LOCK_ACCEPTED}
68 }
69
70 # Setup the notice file to tell bad mirrors they used the wrong time
71 function notice() {
72     rm -f "$NOTICE"
73     cat > "$NOTICE" <<EOF
74 Packages are currently being installed and indices rebuilt.
75 Maintenance is automatic, starting at 01|07|13|19:52 UTC,
76 and ending about an hour later.  This file is then removed.
77
78 You should not mirror the archive during this period.
79 EOF
80 }
81
82 # pushing merkels QA user, part one
83 function merkel1() {
84     log "Telling merkels QA user that we start dinstall"
85     ssh -2 -i ~dak/.ssh/push_merkel_qa  -o BatchMode=yes -o SetupTimeOut=90 -o ConnectTimeout=90 qa@merkel.debian.org sleep 1
86 }
87
88 # Create the postgres dump files
89 function pgdump_pre() {
90     log "Creating pre-daily-cron-job backup of projectb database..."
91     pg_dump projectb > $base/backup/dump_$(date +%Y.%m.%d-%H:%M:%S)
92 }
93
94 function pgdump_post() {
95     log "Creating post-daily-cron-job backup of projectb database..."
96     cd $base/backup
97     POSTDUMP=$base/backup/dump_$(date +%Y.%m.%d-%H:%M:%S)
98     pg_dump projectb > $POSTDUMP
99     ln -sf $POSTDUMP current
100 }
101
102 # Updating various files
103 function updates() {
104     log "Updating Bugs docu, Mirror list and mailing-lists.txt"
105     cd $configdir
106     $scriptsdir/update-bugdoctxt
107     $scriptsdir/update-mirrorlists
108     $scriptsdir/update-mailingliststxt
109     $scriptsdir/update-pseudopackages.sh
110 }
111
112 # Process (oldstable)-proposed-updates "NEW" queue
113 function punew_do() {
114     cd "${queuedir}/${1}"
115     date -u -R >> REPORT
116     dak process-new -a -C COMMENTS >> REPORT || true
117     echo >> REPORT
118 }
119 function punew() {
120     log "Doing automated p-u-new processing"
121     punew_do "$1"
122 }
123 function opunew() {
124     log "Doing automated o-p-u-new processing"
125     punew_do "$1"
126 }
127
128 # The first i18n one, syncing new descriptions
129 function i18n1() {
130     log "Synchronizing i18n package descriptions"
131     # First sync their newest data
132     cd ${scriptdir}/i18nsync
133     rsync -aq --delete --delete-after ddtp-sync:/does/not/matter . || true
134
135     # Now check if we still know about the packages for which they created the files
136     # is the timestamp signed by us?
137     if $(gpgv --keyring /srv/ftp.debian.org/s3kr1t/dot-gnupg/pubring.gpg timestamp.gpg timestamp); then
138         # now read it. As its signed by us we are sure the content is what we expect, no need
139         # to do more here. And we only test -d a directory on it anyway.
140         TSTAMP=$(cat timestamp)
141         # do we have the dir still?
142         if [ -d ${scriptdir}/i18n/${TSTAMP} ]; then
143             # Lets check!
144             if ${scriptsdir}/ddtp-i18n-check.sh . ${scriptdir}/i18n/${TSTAMP}; then
145                 # Yay, worked, lets copy around
146                 for dir in squeeze sid; do
147                     if [ -d dists/${dir}/ ]; then
148                         cd dists/${dir}/main/i18n
149                         rsync -aq --delete --delete-after  . ${ftpdir}/dists/${dir}/main/i18n/.
150                     fi
151                     cd ${scriptdir}/i18nsync
152                 done
153             else
154                 echo "ARRRR, bad guys, wrong files, ARRR"
155                 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
156             fi
157         else
158             echo "ARRRR, missing the timestamp ${TSTAMP} directory, not updating i18n, ARRR"
159             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
160         fi
161     else
162         echo "ARRRRRRR, could not verify our timestamp signature, ARRR. Don't mess with our files, i18n guys, ARRRRR."
163         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
164     fi
165 }
166
167 # Process the accepted queue
168 function accepted() {
169     log "Processing queue/accepted"
170     rm -f "$accepted/REPORT"
171     dak process-accepted -pa -d "$accepted" > "$accepted/REPORT"
172     cat "$accepted/REPORT" | mail -s "Install for $(date +"%D - %R")" ftpmaster@ftp-master.debian.org
173     chgrp debadmin "$accepted/REPORT"
174     chmod 664 "$accepted/REPORT"
175 }
176
177 function cruft() {
178     log "Checking for cruft in overrides"
179     dak check-overrides
180
181     log "Fixing symlinks in $ftpdir"
182     symlinks -d -r $ftpdir
183 }
184
185 function msfl() {
186     log "Generating suite file lists for apt-ftparchive"
187     dak make-suite-file-list
188 }
189
190 function fingerprints() {
191     log "Updating fingerprints"
192     dak import-keyring -L /srv/keyring.debian.org/keyrings/debian-keyring.gpg
193 }
194
195 function overrides() {
196     log "Writing overrides into text files"
197     cd $overridedir
198     dak make-overrides
199
200     # FIXME
201     rm -f override.sid.all3
202     for i in main contrib non-free main.debian-installer; do cat override.sid.$i >> override.sid.all3; done
203 }
204
205 function mpfm() {
206     log "Generating package / file mapping"
207     dak make-pkg-file-mapping | bzip2 -9 > $base/ftp/indices/package-file.map.bz2
208 }
209
210 function packages() {
211     log "Generating Packages and Sources files"
212     cd $configdir
213     apt-ftparchive generate apt.conf
214 }
215
216 function pdiff() {
217     log "Generating pdiff files"
218     dak generate-index-diffs
219 }
220
221 function release() {
222     log "Generating Release files"
223     dak generate-releases
224 }
225
226 function dakcleanup() {
227     log "Cleanup old packages/files"
228     dak clean-suites
229     dak clean-queues
230 }
231
232 function buildd() {
233     # Needs to be rebuilt, as files have moved.  Due to unaccepts, we need to
234     # update this before wanna-build is updated.
235     log "Regenerating wanna-build/buildd information"
236     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
237     symlinks -d /srv/incoming.debian.org/buildd > /dev/null
238     apt-ftparchive generate apt.conf.buildd
239 }
240
241 function scripts() {
242     log "Running various scripts from $scriptsdir"
243     cd $scriptsdir
244     ./mkmaintainers
245     ./copyoverrides
246     ./mklslar
247     ./mkfilesindices
248     ./mkchecksums
249 }
250
251 function mirror() {
252     echo "Regenerating \"public\" mirror/ hardlink fun"
253     cd ${mirrordir}
254     rsync -aH --link-dest ${ftpdir} --delete --delete-after --ignore-errors ${ftpdir}/. .
255 }
256
257 function wb() {
258     log "Trigger daily wanna-build run"
259     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
260 }
261
262 function expire() {
263     log "Expiring old database dumps..."
264     cd $base/backup
265     $scriptsdir/expire_dumps -d . -p -f "dump_*"
266 }
267
268 function reports() {
269     # Send a report on NEW/BYHAND packages
270     log "Nagging ftpteam about NEW/BYHAND packages"
271     dak queue-report | mail -e -s "NEW and BYHAND on $(date +%D)" ftpmaster@ftp-master.debian.org
272     # and one on crufty packages
273     log "Sending information about crufty packages"
274     dak cruft-report > $webdir/cruft-report-daily.txt
275     dak cruft-report -s experimental >> $webdir/cruft-report-daily.txt
276     cat $webdir/cruft-report-daily.txt | mail -e -s "Debian archive cruft report for $(date +%D)" ftpmaster@ftp-master.debian.org
277 }
278
279 function dm() {
280     log "Updating DM html page"
281     $scriptsdir/dm-monitor >$webdir/dm-uploaders.html
282 }
283
284 function bts() {
285     log "Categorizing uncategorized bugs filed against ftp.debian.org"
286     dak bts-categorize
287 }
288
289 function merkel2() {
290     # Push katie@merkel so it syncs the projectb there. Returns immediately, the sync runs detached
291     log "Trigger merkels projectb sync"
292     ssh -2 -o BatchMode=yes -o SetupTimeOut=30 -o ConnectTimeout=30 -i ~/.ssh/push_merkel_projectb katie@merkel.debian.org sleep 1
293 }
294
295 function runparts() {
296     log "Using run-parts to run scripts in $base/scripts/distmnt"
297     run-parts --report $base/scripts/distmnt
298 }
299
300 function i18n2() {
301     log "Exporting package data foo for i18n project"
302     STAMP=$(date "+%Y%m%d%H%M")
303     mkdir -p ${scriptdir}/i18n/${STAMP}
304     cd ${scriptdir}/i18n/${STAMP}
305     dak control-suite -l stable > lenny
306     dak control-suite -l testing > squeeze
307     dak control-suite -l unstable > sid
308     echo "${STAMP}" > timestamp
309     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 6070D3A1 --detach-sign -o timestamp.gpg timestamp
310     rm -f md5sum
311     md5sum * > md5sum
312     cd ${webdir}/
313     ln -sfT ${scriptdir}/i18n/${STAMP} i18n
314
315     cd ${scriptdir}
316     find ./i18n -mindepth 1 -maxdepth 1 -mtime +2 -not -name "${STAMP}" -type d -print0 | xargs --no-run-if-empty -0 rm -rf
317 }
318
319 function stats() {
320     log "Updating stats data"
321     cd $configdir
322     $scriptsdir/update-ftpstats $base/log/* > $base/misc/ftpstats.data
323     R --slave --vanilla < $base/misc/ftpstats.R
324 }
325
326 function aptftpcleanup() {
327     log "Clean up apt-ftparchive's databases"
328     cd $configdir
329     apt-ftparchive -q clean apt.conf
330 }
331
332 function compress() {
333     log "Compress old psql backups"
334     cd $base/backup/
335     find -maxdepth 1 -mindepth 1 -type f -name 'dump_*' \! -name '*.bz2' \! -name '*.gz' -mtime +1 |
336     while read dumpname; do
337         echo "Compressing $dumpname"
338         bzip2 -9v "$dumpname"
339     done
340 }
341
342 function logstats() {
343     $masterdir/tools/logs.py "$LOGFILE"
344 }
345
346 ########################################################################
347 ########################################################################
348
349 # Function to save which stage we are in, so we can restart an interrupted
350 # dinstall. Or even run actions in parallel, if we dare to, by simply
351 # backgrounding the call to this function. But that should only really be
352 # done for things we dont care much about.
353 #
354 # This should be called with the first argument being an array, with the
355 # members
356 #  - FUNC - the function name to call
357 #  - ARGS - Possible arguments to hand to the function. Can be the empty string
358 #  - TS   - The timestamp name. Can be the empty string
359 #  - ERR  - if this is the string false, then the call will be surrounded by
360 #           set +e ... set -e calls, so errors in the function do not exit
361 #           dinstall. Can be the empty string, meaning true.
362 #
363 # MAKE SURE TO KEEP THIS THE LAST FUNCTION, AFTER ALL THE VARIOUS ONES
364 # ADDED FOR DINSTALL FEATURES!
365 function stage() {
366     ARGS='GO[@]'
367     local "${!ARGS}"
368
369     if [ -f "${stagedir}/${FUNC}" ]; then
370         stamptime=$(/usr/bin/stat -c %Z "${stagedir}/${FUNC}")
371         unixtime=$(date +%s)
372         difference=$(( $unixtime - $stamptime ))
373         if [ ${difference} -ge 14400 ]; then
374             log_error "Did already run ${FUNC}, stagefile exists, but that was ${difference} seconds ago. Please check."
375         else
376             log "Did already run ${FUNC}, not calling again..."
377         fi
378         return
379     fi
380
381     debug "Now calling function ${FUNC}. Arguments: ${ARGS}. Timestamp: ${TS}"
382
383     # Make sure we are always at the same place. If a function wants to be elsewhere,
384     # it has to cd first!
385     cd ${configdir}
386
387         if [ -f "${LOCK_STOP}" ]; then
388                 log "${LOCK_STOP} exists, exiting immediately"
389                 exit 42
390         fi
391
392     if [ "${ERR}" = "false" ]; then
393         set +e
394     fi
395     ${FUNC} ${ARGS}
396
397     # No matter what happened in the function, we make sure we have set -e default state back
398     set -e
399
400     # Make sure we are always at the same place.
401     cd ${configdir}
402
403     touch "${stagedir}/${FUNC}"
404
405         if [ -f "${LOCK_STOP}" ]; then
406                 log "${LOCK_STOP} exists, exiting immediately"
407                 exit 42
408         fi
409
410     if [ -n "${TIME}" ]; then
411         ts "${TIME}"
412     fi
413 }
414
415 ########################################################################
416
417 # We need logs.
418 LOGFILE="$logdir/dinstall.log"
419
420 exec >> "$LOGFILE" 2>&1
421
422 # usually we are not using debug logs. Set to 1 if you want them.
423 DEBUG=0
424
425 # our name
426 PROGRAM="dinstall"
427
428 # where do we want mails to go? For example log entries made with error()
429 if [ "x$(hostname -s)x" != "xriesx" ]; then
430     # Not our ftpmaster host
431     MAILTO=${MAILTO:-"root"}
432 else
433     # Yay, ftpmaster
434     MAILTO=${MAILTO:-"ftpmaster@debian.org"}
435 fi
436
437 # How many logfiles to keep
438 LOGROTATE=${LOGROTATE:-400}
439
440 # Timestamps start at -1. so first gets 0
441 TS=-1
442 ts "startup"
443
444 # Tell everyone we are doing some work
445 NOTICE="$ftpdir/Archive_Maintenance_In_Progress"
446
447 # lock cron.unchecked (it immediately exits when this exists)
448 LOCK_DAILY="$lockdir/daily.lock"
449
450 # Lock process-new and cron.unchecked from doing work
451 LOCK_ACCEPTED="$lockdir/unchecked.lock"
452
453 # This file is simply used to indicate to britney whether or not
454 # the Packages file updates completed sucessfully.  It's not a lock
455 # from our point of view
456 LOCK_BRITNEY="$lockdir/britney.lock"
457
458 # If this file exists we exit immediately after the currently running
459 # function is done
460 LOCK_STOP="$lockdir/archive.stop"
461
462 lockfile -l 3600 "${LOCK_DAILY}"
463 trap cleanup EXIT ERR TERM HUP INT QUIT
464
465 touch "${LOCK_BRITNEY}"
466
467 GO=(
468     FUNC="notice"
469     TIME=""
470     ARGS=""
471     ERR="false"
472 )
473 stage $GO
474
475 GO=(
476     FUNC="merkel1"
477     TIME="init"
478     ARGS=""
479     ERR="false"
480 )
481 stage $GO
482
483 GO=(
484     FUNC="pgdump_pre"
485     TIME="pg_dump1"
486     ARGS=""
487     ERR=""
488 )
489 stage $GO
490
491 GO=(
492     FUNC="updates"
493     TIME="External Updates"
494     ARGS=""
495     ERR="false"
496 )
497 stage $GO
498
499 GO=(
500     FUNC="punew"
501     TIME="p-u-new"
502     ARGS="p-u-new"
503     ERR=""
504 )
505 stage $GO
506
507 GO=(
508     FUNC="opunew"
509     TIME="o-p-u-new"
510     ARGS="o-p-u-new"
511     ERR=""
512 )
513 stage $GO
514
515 GO=(
516     FUNC="i18n1"
517     TIME="i18n 1"
518     ARGS=""
519     ERR="false"
520 )
521 stage $GO
522
523 lockfile "$LOCK_ACCEPTED"
524
525 GO=(
526     FUNC="accepted"
527     TIME="accepted"
528     ARGS=""
529     ERR=""
530 )
531 stage $GO
532
533 GO=(
534     FUNC="cruft"
535     TIME="cruft"
536     ARGS=""
537     ERR=""
538 )
539 stage $GO
540
541 rm -f "$LOCK_ACCEPTED"
542
543 GO=(
544     FUNC="msfl"
545     TIME="make-suite-file-list"
546     ARGS=""
547     ERR=""
548 )
549 stage $GO
550
551 GO=(
552     FUNC="fingerprints"
553     TIME="import-keyring"
554     ARGS=""
555     ERR="false"
556 )
557 stage $GO
558
559 GO=(
560     FUNC="overrides"
561     TIME="overrides"
562     ARGS=""
563     ERR=""
564 )
565 stage $GO
566
567 GO=(
568     FUNC="mpfm"
569     TIME="pkg-file-mapping"
570     ARGS=""
571     ERR="false"
572 )
573 stage $GO
574
575 GO=(
576     FUNC="packages"
577     TIME="apt-ftparchive"
578     ARGS=""
579     ERR=""
580 )
581 stage $GO
582
583 GO=(
584     FUNC="pdiff"
585     TIME="pdiff"
586     ARGS=""
587     ERR=""
588 )
589 stage $GO
590
591 GO=(
592     FUNC="release"
593     TIME="release files"
594     ARGS=""
595     ERR=""
596 )
597 stage $GO
598
599 GO=(
600     FUNC="dakcleanup"
601     TIME="cleanup"
602     ARGS=""
603     ERR=""
604 )
605 stage $GO
606
607 GO=(
608     FUNC="buildd"
609     TIME="buildd"
610     ARGS=""
611     ERR=""
612 )
613 stage $GO
614
615 GO=(
616     FUNC="scripts"
617     TIME="scripts"
618     ARGS=""
619     ERR=""
620 )
621 stage $GO
622
623 GO=(
624     FUNC="mirror"
625     TIME="mirror hardlinks"
626     ARGS=""
627     ERR=""
628 )
629 stage $GO
630
631 GO=(
632     FUNC="wb"
633     TIME="w-b"
634     ARGS=""
635     ERR=""
636 )
637 stage $GO
638
639 rm -f "${NOTICE}"
640 rm -f "${LOCK_DAILY}"
641
642 ts "locked part finished"
643
644 GO=(
645     FUNC="pgdump_post"
646     TIME="pg_dump2"
647     ARGS=""
648     ERR=""
649 )
650 stage $GO
651
652 GO=(
653     FUNC="expire"
654     TIME="expire_dumps"
655     ARGS=""
656     ERR=""
657 )
658 stage $GO
659
660 GO=(
661     FUNC="reports"
662     TIME="reports"
663     ARGS=""
664     ERR=""
665 )
666 stage $GO
667
668 GO=(
669     FUNC="dm"
670     TIME=""
671     ARGS=""
672     ERR=""
673 )
674 stage $GO
675
676 GO=(
677     FUNC="bts"
678     TIME=""
679     ARGS=""
680     ERR=""
681 )
682 stage $GO
683
684 GO=(
685     FUNC="merkel2"
686     TIME="merkel projectb push"
687     ARGS=""
688     ERR="false"
689 )
690 stage $GO
691
692 ulimit -m 90000 -d 90000 -s 10000 -v 200000
693
694 GO=(
695     FUNC="runparts"
696     TIME="run-parts"
697     ARGS=""
698     ERR="false"
699 )
700 stage $GO
701
702 GO=(
703     FUNC="i18n2"
704     TIME="i18n 2"
705     ARGS=""
706     ERR="false"
707 )
708 stage $GO
709
710 GO=(
711     FUNC="stats"
712     TIME="stats"
713     ARGS=""
714     ERR="false"
715 )
716 stage $GO
717
718 rm -f ${LOCK_BRITNEY}
719
720 GO=(
721     FUNC="aptftpcleanup"
722     TIME="apt-ftparchive cleanup"
723     ARGS=""
724     ERR=""
725 )
726 stage $GO
727
728 GO=(
729     FUNC="compress"
730     TIME="compress"
731     ARGS=""
732     ERR=""
733 )
734 stage $GO
735
736 log "Daily cron scripts successful, all done"
737
738 exec > /dev/null 2>&1
739
740 GO=(
741     FUNC="logstats"
742     TIME=""
743     ARGS=""
744     ERR=""
745 )
746 stage $GO
747
748 cat "$LOGFILE" | mail -s "Log for dinstall run of ${NOW}" cron@ftp-master.debian.org
749
750 savelog -c ${LOGROTATE} -j "$LOGFILE"
751
752 # Now, at the very (successful) end of dinstall, make sure we remove
753 # our stage files, so the next dinstall run will do it all again.
754 rm -f "${stagedir}/*"