]> git.decadent.org.uk Git - dak.git/blob - config/debian/dinstall
dinstall
[dak.git] / config / debian / 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     cd "$accepted"
171     rm -f REPORT
172     dak process-accepted -pa *.changes > REPORT
173     cat REPORT | mail -s "Install for $(date +"%D - %R")" ftpmaster@ftp-master.debian.org
174     chgrp debadmin REPORT
175     chmod 664 REPORT
176 }
177
178 function cruft() {
179     log "Checking for cruft in overrides"
180     dak check-overrides
181
182     log "Fixing symlinks in $ftpdir"
183     symlinks -d -r $ftpdir
184 }
185
186 function msfl() {
187     log "Generating suite file lists for apt-ftparchive"
188     dak make-suite-file-list
189 }
190
191 function fingerprints() {
192     log "Updating fingerprints"
193     dak import-keyring -L /srv/keyring.debian.org/keyrings/debian-keyring.gpg
194 }
195
196 function overrides() {
197     log "Writing overrides into text files"
198     cd $overridedir
199     dak make-overrides
200
201     # FIXME
202     rm -f override.sid.all3
203     for i in main contrib non-free main.debian-installer; do cat override.sid.$i >> override.sid.all3; done
204 }
205
206 function mpfm() {
207     log "Generating package / file mapping"
208     dak make-pkg-file-mapping | bzip2 -9 > $base/ftp/indices/package-file.map.bz2
209 }
210
211 function packages() {
212     log "Generating Packages and Sources files"
213     cd $configdir
214     apt-ftparchive generate apt.conf
215 }
216
217 function pdiff() {
218     log "Generating pdiff files"
219     dak generate-index-diffs
220 }
221
222 function release() {
223     log "Generating Release files"
224     dak generate-releases
225 }
226
227 function dakcleanup() {
228     log "Cleanup old packages/files"
229     dak clean-suites
230     dak clean-queues
231 }
232
233 function buildd() {
234     # Needs to be rebuilt, as files have moved.  Due to unaccepts, we need to
235     # update this before wanna-build is updated.
236     log "Regenerating wanna-build/buildd information"
237     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
238     symlinks -d /srv/incoming.debian.org/buildd > /dev/null
239     apt-ftparchive generate apt.conf.buildd
240 }
241
242 function scripts() {
243     log "Running various scripts from $scriptsdir"
244     cd $scriptsdir
245     ./mkmaintainers
246     ./copyoverrides
247     ./mklslar
248     ./mkfilesindices
249     ./mkchecksums
250 }
251
252 function mirror() {
253     echo "Regenerating \"public\" mirror/ hardlink fun"
254     cd ${mirrordir}
255     rsync -aH --link-dest ${ftpdir} --delete --delete-after --ignore-errors ${ftpdir}/. .
256 }
257
258 function wb() {
259     log "Trigger daily wanna-build run"
260     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
261 }
262
263 function expire() {
264     log "Expiring old database dumps..."
265     cd $base/backup
266     $scriptsdir/expire_dumps -d . -p -f "dump_*"
267 }
268
269 function reports() {
270     # Send a report on NEW/BYHAND packages
271     log "Nagging ftpteam about NEW/BYHAND packages"
272     dak queue-report | mail -e -s "NEW and BYHAND on $(date +%D)" ftpmaster@ftp-master.debian.org
273     # and one on crufty packages
274     log "Sending information about crufty packages"
275     dak cruft-report > $webdir/cruft-report-daily.txt
276     dak cruft-report -s experimental >> $webdir/cruft-report-daily.txt
277     cat $webdir/cruft-report-daily.txt | mail -e -s "Debian archive cruft report for $(date +%D)" ftpmaster@ftp-master.debian.org
278 }
279
280 function dm() {
281     log "Updating DM html page"
282     $scriptsdir/dm-monitor >$webdir/dm-uploaders.html
283 }
284
285 function bts() {
286     log "Categorizing uncategorized bugs filed against ftp.debian.org"
287     dak bts-categorize
288 }
289
290 function merkel2() {
291     # Push katie@merkel so it syncs the projectb there. Returns immediately, the sync runs detached
292     log "Trigger merkels projectb sync"
293     ssh -2 -o BatchMode=yes -o SetupTimeOut=30 -o ConnectTimeout=30 -i ~/.ssh/push_merkel_projectb katie@merkel.debian.org sleep 1
294 }
295
296 function runparts() {
297     log "Using run-parts to run scripts in $base/scripts/distmnt"
298     run-parts --report $base/scripts/distmnt
299 }
300
301 function i18n2() {
302     log "Exporting package data foo for i18n project"
303     STAMP=$(date "+%Y%m%d%H%M")
304     mkdir -p ${scriptdir}/i18n/${STAMP}
305     cd ${scriptdir}/i18n/${STAMP}
306     dak control-suite -l stable > lenny
307     dak control-suite -l testing > squeeze
308     dak control-suite -l unstable > sid
309     echo "${STAMP}" > timestamp
310     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
311     rm -f md5sum
312     md5sum * > md5sum
313     cd ${webdir}/
314     ln -sfT ${scriptdir}/i18n/${STAMP} i18n
315
316     cd ${scriptdir}
317     find ./i18n -mtime +2 -mindepth 1 -maxdepth 1 -not -name "${STAMP}" -type d -print0 | xargs --no-run-if-empty -0 rm -rf
318 }
319
320 function stats() {
321     log "Updating stats data"
322     cd $configdir
323     $scriptsdir/update-ftpstats $base/log/* > $base/misc/ftpstats.data
324     R --slave --vanilla < $base/misc/ftpstats.R
325 }
326
327 function aptftpcleanup() {
328     log "Clean up apt-ftparchive's databases"
329     cd $configdir
330     apt-ftparchive -q clean apt.conf
331 }
332
333 function compress() {
334     log "Compress old psql backups"
335     cd $base/backup/
336     find -maxdepth 1 -mindepth 1 -type f -name 'dump_*' \! -name '*.bz2' \! -name '*.gz' -mtime +1 |
337     while read dumpname; do
338         echo "Compressing $dumpname"
339         bzip2 -9v "$dumpname"
340     done
341 }
342
343 function logstats() {
344     $masterdir/tools/logs.py "$LOGFILE"
345 }
346
347 ########################################################################
348 ########################################################################
349
350 # Function to save which stage we are in, so we can restart an interrupted
351 # dinstall. Or even run actions in parallel, if we dare to, by simply
352 # backgrounding the call to this function. But that should only really be
353 # done for things we dont care much about.
354 #
355 # This should be called with the first argument being an array, with the
356 # members
357 #  - FUNC - the function name to call
358 #  - ARGS - Possible arguments to hand to the function. Can be the empty string
359 #  - TS   - The timestamp name. Can be the empty string
360 #  - ERR  - if this is the string false, then the call will be surrounded by
361 #           set +e ... set -e calls, so errors in the function do not exit
362 #           dinstall. Can be the empty string, meaning true.
363 #
364 # MAKE SURE TO KEEP THIS THE LAST FUNCTION, AFTER ALL THE VARIOUS ONES
365 # ADDED FOR DINSTALL FEATURES!
366 function stage() {
367     ARGS='GO[@]'
368     local "${!ARGS}"
369
370     if [ -f "${stagedir}/${FUNC}" ]; then
371         stamptime=$(/usr/bin/stat -c %Z "${stagedir}/${FUNC}")
372         unixtime=$(date +%s)
373         difference=$(( $unixtime - $stamptime ))
374         if [ ${difference} -ge 14400 ]; then
375             log_error "Did already run ${FUNC}, stagefile exists, but that was ${difference} seconds ago. Please check."
376         else
377             log "Did already run ${FUNC}, not calling again..."
378         fi
379         return
380     fi
381
382     debug "Now calling function ${FUNC}. Arguments: ${ARGS}. Timestamp: ${TS}"
383
384     # Make sure we are always at the same place. If a function wants to be elsewhere,
385     # it has to cd first!
386     cd ${configdir}
387
388         if [ -f "${LOCK_STOP}" ]; then
389                 log "${LOCK_STOP} exists, exiting immediately"
390                 exit 42
391         fi
392
393     if [ "${ERR}" = "false" ]; then
394         set +e
395     fi
396     ${FUNC} ${ARGS}
397
398     # No matter what happened in the function, we make sure we have set -e default state back
399     set -e
400
401     # Make sure we are always at the same place.
402     cd ${configdir}
403
404     touch "${stagedir}/${FUNC}"
405
406         if [ -f "${LOCK_STOP}" ]; then
407                 log "${LOCK_STOP} exists, exiting immediately"
408                 exit 42
409         fi
410
411     if [ -n "${TIME}" ]; then
412         ts "${TIME}"
413     fi
414 }
415
416 ########################################################################
417
418 # We need logs.
419 LOGFILE="$logdir/dinstall.log"
420
421 exec >> "$LOGFILE" 2>&1
422
423 # usually we are not using debug logs. Set to 1 if you want them.
424 DEBUG=0
425
426 # our name
427 PROGRAM="dinstall"
428
429 # where do we want mails to go? For example log entries made with error()
430 if [ "x$(hostname -s)x" != "xriesx" ]; then
431     # Not our ftpmaster host
432     MAILTO=${MAILTO:-"root"}
433 else
434     # Yay, ftpmaster
435     MAILTO=${MAILTO:-"ftpmaster@debian.org"}
436 fi
437
438 # How many logfiles to keep
439 LOGROTATE=${LOGROTATE:-400}
440
441 # Timestamps start at -1. so first gets 0
442 TS=-1
443 ts "startup"
444
445 # Tell everyone we are doing some work
446 NOTICE="$ftpdir/Archive_Maintenance_In_Progress"
447
448 # lock cron.unchecked (it immediately exits when this exists)
449 LOCK_DAILY="$lockdir/daily.lock"
450
451 # Lock process-new and cron.unchecked from doing work
452 LOCK_ACCEPTED="$lockdir/unchecked.lock"
453
454 # This file is simply used to indicate to britney whether or not
455 # the Packages file updates completed sucessfully.  It's not a lock
456 # from our point of view
457 LOCK_BRITNEY="$lockdir/britney.lock"
458
459 # If this file exists we exit immediately after the currently running
460 # function is done
461 LOCK_STOP="$lockdir/archive.stop"
462
463 lockfile -l 3600 "${LOCK_DAILY}"
464 trap cleanup EXIT ERR TERM HUP INT QUIT
465
466 touch "${LOCK_BRITNEY}"
467
468 GO=(
469     FUNC="notice"
470     TIME=""
471     ARGS=""
472     ERR="false"
473 )
474 stage $GO
475
476 GO=(
477     FUNC="merkel1"
478     TIME="init"
479     ARGS=""
480     ERR="false"
481 )
482 stage $GO
483
484 GO=(
485     FUNC="pgdump_pre"
486     TIME="pg_dump1"
487     ARGS=""
488     ERR=""
489 )
490 stage $GO
491
492 GO=(
493     FUNC="updates"
494     TIME="External Updates"
495     ARGS=""
496     ERR="false"
497 )
498 stage $GO
499
500 GO=(
501     FUNC="punew"
502     TIME="p-u-new"
503     ARGS="p-u-new"
504     ERR=""
505 )
506 stage $GO
507
508 GO=(
509     FUNC="opunew"
510     TIME="o-p-u-new"
511     ARGS="o-p-u-new"
512     ERR=""
513 )
514 stage $GO
515
516 GO=(
517     FUNC="i18n1"
518     TIME="i18n 1"
519     ARGS=""
520     ERR="false"
521 )
522 stage $GO
523
524 lockfile "$LOCK_ACCEPTED"
525
526 GO=(
527     FUNC="accepted"
528     TIME="accepted"
529     ARGS=""
530     ERR=""
531 )
532 stage $GO
533
534 GO=(
535     FUNC="cruft"
536     TIME="cruft"
537     ARGS=""
538     ERR=""
539 )
540 stage $GO
541
542 rm -f "$LOCK_ACCEPTED"
543
544 GO=(
545     FUNC="msfl"
546     TIME="make-suite-file-list"
547     ARGS=""
548     ERR=""
549 )
550 stage $GO
551
552 GO=(
553     FUNC="fingerprints"
554     TIME="import-keyring"
555     ARGS=""
556     ERR="false"
557 )
558 stage $GO
559
560 GO=(
561     FUNC="overrides"
562     TIME="overrides"
563     ARGS=""
564     ERR=""
565 )
566 stage $GO
567
568 GO=(
569     FUNC="mpfm"
570     TIME="pkg-file-mapping"
571     ARGS=""
572     ERR="false"
573 )
574 stage $GO
575
576 GO=(
577     FUNC="packages"
578     TIME="apt-ftparchive"
579     ARGS=""
580     ERR=""
581 )
582 stage $GO
583
584 GO=(
585     FUNC="pdiff"
586     TIME="pdiff"
587     ARGS=""
588     ERR=""
589 )
590 stage $GO
591
592 GO=(
593     FUNC="release"
594     TIME="release files"
595     ARGS=""
596     ERR=""
597 )
598 stage $GO
599
600 GO=(
601     FUNC="dakcleanup"
602     TIME="cleanup"
603     ARGS=""
604     ERR=""
605 )
606 stage $GO
607
608 GO=(
609     FUNC="buildd"
610     TIME="buildd"
611     ARGS=""
612     ERR=""
613 )
614 stage $GO
615
616 GO=(
617     FUNC="scripts"
618     TIME="scripts"
619     ARGS=""
620     ERR=""
621 )
622 stage $GO
623
624 GO=(
625     FUNC="mirror"
626     TIME="mirror hardlinks"
627     ARGS=""
628     ERR=""
629 )
630 stage $GO
631
632 GO=(
633     FUNC="wb"
634     TIME="w-b"
635     ARGS=""
636     ERR=""
637 )
638 stage $GO
639
640 rm -f "${NOTICE}"
641 rm -f "${LOCK_DAILY}"
642
643 ts "locked part finished"
644
645 GO=(
646     FUNC="pgdump_post"
647     TIME="pg_dump2"
648     ARGS=""
649     ERR=""
650 )
651 stage $GO
652
653 GO=(
654     FUNC="expire"
655     TIME="expire_dumps"
656     ARGS=""
657     ERR=""
658 )
659 stage $GO
660
661 GO=(
662     FUNC="reports"
663     TIME="reports"
664     ARGS=""
665     ERR=""
666 )
667 stage $GO
668
669 GO=(
670     FUNC="dm"
671     TIME=""
672     ARGS=""
673     ERR=""
674 )
675 stage $GO
676
677 GO=(
678     FUNC="bts"
679     TIME=""
680     ARGS=""
681     ERR=""
682 )
683 stage $GO
684
685 GO=(
686     FUNC="merkel2"
687     TIME="merkel projectb push"
688     ARGS=""
689     ERR="false"
690 )
691 stage $GO
692
693 ulimit -m 90000 -d 90000 -s 10000 -v 200000
694
695 GO=(
696     FUNC="runparts"
697     TIME="run-parts"
698     ARGS=""
699     ERR="false"
700 )
701 stage $GO
702
703 GO=(
704     FUNC="i18n2"
705     TIME="i18n 2"
706     ARGS=""
707     ERR="false"
708 )
709 stage $GO
710
711 GO=(
712     FUNC="stats"
713     TIME="stats"
714     ARGS=""
715     ERR="false"
716 )
717 stage $GO
718
719 rm -f ${BRITNEYLOCK}
720
721 GO=(
722     FUNC="aptftpcleanup"
723     TIME="apt-ftparchive cleanup"
724     ARGS=""
725     ERR=""
726 )
727 stage $GO
728
729 GO=(
730     FUNC="compress"
731     TIME="compress"
732     ARGS=""
733     ERR=""
734 )
735 stage $GO
736
737 log "Daily cron scripts successful, all done"
738
739 exec > /dev/null 2>&1
740
741 GO=(
742     FUNC="logstats"
743     TIME=""
744     ARGS=""
745     ERR=""
746 )
747 stage $GO
748
749 cat "$LOGFILE" | mail -s "Log for dinstall run of ${NOW}" cron@ftp-master.debian.org
750
751 savelog -c ${LOGROTATE} -j "$LOGFILE"
752
753 # Now, at the very (successful) end of dinstall, make sure we remove
754 # our stage files, so the next dinstall run will do it all again.
755 rm -f "${stagedir}/*"