]> 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 }
68
69 # Setup the notice file to tell bad mirrors they used the wrong time
70 function notice() {
71     rm -f "$NOTICE"
72     cat > "$NOTICE" <<EOF
73 Packages are currently being installed and indices rebuilt.
74 Maintenance is automatic, starting at 01|07|13|19:52 UTC,
75 and ending about an hour later.  This file is then removed.
76
77 You should not mirror the archive during this period.
78 EOF
79 }
80
81 # pushing merkels QA user, part one
82 function merkel1() {
83     log "Telling merkels QA user that we start dinstall"
84     ssh -2 -i ~dak/.ssh/push_merkel_qa  -o BatchMode=yes -o SetupTimeOut=90 -o ConnectTimeout=90 qa@merkel.debian.org sleep 1
85 }
86
87 # Create the postgres dump files
88 function pgdump_pre() {
89     log "Creating pre-daily-cron-job backup of projectb database..."
90     pg_dump projectb > $base/backup/dump_$(date +%Y.%m.%d-%H:%M:%S)
91 }
92
93 function pgdump_post() {
94     log "Creating post-daily-cron-job backup of projectb database..."
95     cd $base/backup
96     POSTDUMP=$base/backup/dump_$(date +%Y.%m.%d-%H:%M:%S)
97     pg_dump projectb > $POSTDUMP
98     ln -sf $POSTDUMP current
99 }
100
101 # Updating various files
102 function updates() {
103     log "Updating Bugs docu, Mirror list and mailing-lists.txt"
104     cd $configdir
105     $scriptsdir/update-bugdoctxt
106     $scriptsdir/update-mirrorlists
107     $scriptsdir/update-mailingliststxt
108     $scriptsdir/update-pseudopackages.sh
109 }
110
111 # Process (oldstable)-proposed-updates "NEW" queue
112 function punew_do() {
113     cd "${queuedir}/${1}"
114     date -u -R >> REPORT
115     dak process-new -a -C COMMENTS >> REPORT || true
116     echo >> REPORT
117 }
118 function punew() {
119     log "Doing automated p-u-new processing"
120     punew_do "$1"
121 }
122 function opunew() {
123     log "Doing automated o-p-u-new processing"
124     punew_do "$1"
125 }
126
127 # The first i18n one, syncing new descriptions
128 function i18n1() {
129     log "Synchronizing i18n package descriptions"
130     # First sync their newest data
131     cd ${scriptdir}/i18nsync
132     rsync -aq --delete --delete-after ddtp-sync:/does/not/matter . || true
133
134     # Now check if we still know about the packages for which they created the files
135     # is the timestamp signed by us?
136     if $(gpgv --keyring /srv/ftp.debian.org/s3kr1t/dot-gnupg/pubring.gpg timestamp.gpg timestamp); then
137         # now read it. As its signed by us we are sure the content is what we expect, no need
138         # to do more here. And we only test -d a directory on it anyway.
139         TSTAMP=$(cat timestamp)
140         # do we have the dir still?
141         if [ -d ${scriptdir}/i18n/${TSTAMP} ]; then
142             # Lets check!
143             if ${scriptsdir}/ddtp-i18n-check.sh . ${scriptdir}/i18n/${TSTAMP}; then
144                 # Yay, worked, lets copy around
145                 for dir in squeeze sid; do
146                     if [ -d dists/${dir}/ ]; then
147                         cd dists/${dir}/main/i18n
148                         rsync -aq --delete --delete-after  . ${ftpdir}/dists/${dir}/main/i18n/.
149                     fi
150                     cd ${scriptdir}/i18nsync
151                 done
152             else
153                 echo "ARRRR, bad guys, wrong files, ARRR"
154                 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
155             fi
156         else
157             echo "ARRRR, missing the timestamp ${TSTAMP} directory, not updating i18n, ARRR"
158             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
159         fi
160     else
161         echo "ARRRRRRR, could not verify our timestamp signature, ARRR. Don't mess with our files, i18n guys, ARRRRR."
162         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
163     fi
164 }
165
166 # Process the accepted queue
167 function accepted() {
168     log "Processing queue/accepted"
169     cd "$accepted"
170     rm -f REPORT
171     dak process-accepted -pa *.changes > REPORT
172     cat REPORT | mail -s "Install for $(date +"%D - %R")" ftpmaster@ftp-master.debian.org
173     chgrp debadmin REPORT
174     chmod 664 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 -mtime +2 -mindepth 1 -maxdepth 1 -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 [ "${ERR}" = "false" ]; then
388         set +e
389     fi
390     ${FUNC} ${ARGS}
391
392     # No matter what happened in the function, we make sure we have set -e default state back
393     set -e
394
395     # Make sure we are always at the same place.
396     cd ${configdir}
397
398     touch "${stagedir}/${FUNC}"
399
400     if [ -n "${TIME}" ]; then
401         ts "${TIME}"
402     fi
403 }
404
405 ########################################################################
406
407 # We need logs.
408 LOGFILE="$logdir/dinstall.log"
409
410 exec >> "$LOGFILE" 2>&1
411
412 # usually we are not using debug logs. Set to 1 if you want them.
413 DEBUG=0
414
415 # our name
416 PROGRAM="dinstall"
417
418 # where do we want mails to go? For example log entries made with error()
419 if [ "x$(hostname -s)x" != "xriesx" ]; then
420     # Not our ftpmaster host
421     MAILTO=${MAILTO:-"root"}
422 else
423     # Yay, ftpmaster
424     MAILTO=${MAILTO:-"ftpmaster@debian.org"}
425 fi
426
427 # How many logfiles to keep
428 LOGROTATE=${LOGROTATE:-400}
429
430 # Timestamps start at -1. so first gets 0
431 TS=-1
432 ts "startup"
433
434 # Tell everyone we are doing some work
435 NOTICE="$ftpdir/Archive_Maintenance_In_Progress"
436
437 # lock cron.unchecked (it immediately exits when this exists)
438 LOCK_DAILY="$lockdir/daily.lock"
439
440 # Lock process-new and cron.unchecked from doing work
441 LOCK_ACCEPTED="$lockdir/unchecked.lock"
442
443 # This file is simply used to indicate to britney whether or not
444 # the Packages file updates completed sucessfully.  It's not a lock
445 # from our point of view
446 LOCK_BRITNEY="$lockdir/britney.lock"
447
448 lockfile -l 3600 "${LOCK_DAILY}"
449 trap cleanup EXIT ERR TERM HUP INT QUIT
450
451 touch "${LOCK_BRITNEY}"
452
453 GO=(
454     FUNC="notice"
455     TIME=""
456     ARGS=""
457     ERR="false"
458 )
459 stage $GO
460
461 GO=(
462     FUNC="merkel1"
463     TIME="init"
464     ARGS=""
465     ERR="false"
466 )
467 stage $GO
468
469 GO=(
470     FUNC="pgdump_pre"
471     TIME="pg_dump1"
472     ARGS=""
473     ERR=""
474 )
475 stage $GO
476
477 GO=(
478     FUNC="updates"
479     TIME="External Updates"
480     ARGS=""
481     ERR="false"
482 )
483 stage $GO
484
485 GO=(
486     FUNC="punew"
487     TIME="p-u-new"
488     ARGS="p-u-new"
489     ERR=""
490 )
491 stage $GO
492
493 GO=(
494     FUNC="opunew"
495     TIME="o-p-u-new"
496     ARGS="o-p-u-new"
497     ERR=""
498 )
499 stage $GO
500
501 GO=(
502     FUNC="i18n1"
503     TIME="i18n 1"
504     ARGS=""
505     ERR="false"
506 )
507 stage $GO
508
509 lockfile "$LOCK_ACCEPTED"
510
511 GO=(
512     FUNC="accepted"
513     TIME="accepted"
514     ARGS=""
515     ERR=""
516 )
517 stage $GO
518
519 GO=(
520     FUNC="cruft"
521     TIME="cruft"
522     ARGS=""
523     ERR=""
524 )
525 stage $GO
526
527 rm -f $LOCKAC
528
529 GO=(
530     FUNC="msfl"
531     TIME="make-suite-file-list"
532     ARGS=""
533     ERR=""
534 )
535 stage $GO
536
537 GO=(
538     FUNC="fingerprints"
539     TIME="import-keyring"
540     ARGS=""
541     ERR="false"
542 )
543 stage $GO
544
545 GO=(
546     FUNC="overrides"
547     TIME="overrides"
548     ARGS=""
549     ERR=""
550 )
551 stage $GO
552
553 GO=(
554     FUNC="mpfm"
555     TIME="pkg-file-mapping"
556     ARGS=""
557     ERR="false"
558 )
559 stage $GO
560
561 GO=(
562     FUNC="packages"
563     TIME="apt-ftparchive"
564     ARGS=""
565     ERR=""
566 )
567 stage $GO
568
569 GO=(
570     FUNC="pdiff"
571     TIME="pdiff"
572     ARGS=""
573     ERR=""
574 )
575 stage $GO
576
577 GO=(
578     FUNC="release"
579     TIME="release files"
580     ARGS=""
581     ERR=""
582 )
583 stage $GO
584
585 GO=(
586     FUNC="dakcleanup"
587     TIME="cleanup"
588     ARGS=""
589     ERR=""
590 )
591 stage $GO
592
593 GO=(
594     FUNC="buildd"
595     TIME="buildd"
596     ARGS=""
597     ERR=""
598 )
599 stage $GO
600
601 GO=(
602     FUNC="scripts"
603     TIME="scripts"
604     ARGS=""
605     ERR=""
606 )
607 stage $GO
608
609 GO=(
610     FUNC="mirror"
611     TIME="mirror hardlinks"
612     ARGS=""
613     ERR=""
614 )
615 stage $GO
616
617 GO=(
618     FUNC="wb"
619     TIME="w-b"
620     ARGS=""
621     ERR=""
622 )
623 stage $GO
624
625 rm -f "${NOTICE}"
626 rm -f "${LOCK_DAILY}"
627
628 ts "locked part finished"
629
630 GO=(
631     FUNC="pgdump_post"
632     TIME="pg_dump2"
633     ARGS=""
634     ERR=""
635 )
636 stage $GO
637
638 GO=(
639     FUNC="expire"
640     TIME="expire_dumps"
641     ARGS=""
642     ERR=""
643 )
644 stage $GO
645
646 GO=(
647     FUNC="reports"
648     TIME="reports"
649     ARGS=""
650     ERR=""
651 )
652 stage $GO
653
654 GO=(
655     FUNC="dm"
656     TIME=""
657     ARGS=""
658     ERR=""
659 )
660 stage $GO
661
662 GO=(
663     FUNC="bts"
664     TIME=""
665     ARGS=""
666     ERR=""
667 )
668 stage $GO
669
670 GO=(
671     FUNC="merkel2"
672     TIME="merkel projectb push"
673     ARGS=""
674     ERR="false"
675 )
676 stage $GO
677
678 ulimit -m 90000 -d 90000 -s 10000 -v 200000
679
680 GO=(
681     FUNC="runparts"
682     TIME="run-parts"
683     ARGS=""
684     ERR="false"
685 )
686 stage $GO
687
688 GO=(
689     FUNC="i18n2"
690     TIME="i18n 2"
691     ARGS=""
692     ERR="false"
693 )
694 stage $GO
695
696 GO=(
697     FUNC="stats"
698     TIME="stats"
699     ARGS=""
700     ERR="false"
701 )
702 stage $GO
703
704 rm -f ${BRITNEYLOCK}
705
706 GO=(
707     FUNC="aptftpcleanup"
708     TIME="apt-ftparchive cleanup"
709     ARGS=""
710     ERR=""
711 )
712 stage $GO
713
714 GO=(
715     FUNC="compress"
716     TIME="compress"
717     ARGS=""
718     ERR=""
719 )
720 stage $GO
721
722 log "Daily cron scripts successful, all done"
723
724 exec > /dev/null 2>&1
725
726 GO=(
727     FUNC="logstats"
728     TIME=""
729     ARGS=""
730     ERR=""
731 )
732 stage $GO
733
734 cat "$LOGFILE" | mail -s "Log for dinstall run of ${NOW}" cron@ftp-master.debian.org
735
736 savelog -c ${LOGROTATE} -j "$LOGFILE"
737
738 # Now, at the very (successful) end of dinstall, make sure we remove
739 # our stage files, so the next dinstall run will do it all again.
740 rm -f "${stagedir}/*"