]> git.decadent.org.uk Git - dak.git/blob - config/debian/dinstall
28c7ad1d0a3f7375a0e1aa464f3bd4adccf886e3
[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     savelog -c ${LOGROTATE} -j "$LOGFILE"
67         rm -f ${LOCK_DAILY}
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 | tee REPORT | \
173         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 [ "${ERR}" = "false" ]; then
389         set +e
390     fi
391     ${FUNC} ${ARGS}
392
393     # No matter what happened in the function, we make sure we have set -e default state back
394     set -e
395
396     # Make sure we are always at the same place.
397     cd ${configdir}
398
399     touch "${stagedir}/${FUNC}"
400
401     if [ -n "${TIME}" ]; then
402         ts "${TIME}"
403     fi
404 }
405
406 ########################################################################
407
408 # We need logs.
409 LOGFILE="$logdir/dinstall.log"
410
411 exec >> "$LOGFILE" 2>&1
412
413 # usually we are not using debug logs. Set to 1 if you want them.
414 DEBUG=0
415
416 # our name
417 PROGRAM="dinstall"
418
419 # where do we want mails to go? For example log entries made with error()
420 if [ "x$(hostname -s)x" != "xriesx" ]; then
421     # Not our ftpmaster host
422     MAILTO=${MAILTO:-"root"}
423 else
424     # Yay, ftpmaster
425     MAILTO=${MAILTO:-"ftpmaster@debian.org"}
426 fi
427
428 # How many logfiles to keep
429 LOGROTATE=${LOGROTATE:-400}
430
431 # Timestamps start at -1. so first gets 0
432 TS=-1
433 ts "startup"
434
435 # Tell everyone we are doing some work
436 NOTICE="$ftpdir/Archive_Maintenance_In_Progress"
437
438 # lock cron.unchecked (it immediately exits when this exists)
439 LOCK_DAILY="$lockdir/daily.lock"
440
441 # Lock process-new and cron.unchecked from doing work
442 LOCK_ACCEPTED="$lockdir/unchecked.lock"
443
444 # This file is simply used to indicate to britney whether or not
445 # the Packages file updates completed sucessfully.  It's not a lock
446 # from our point of view
447 LOCK_BRITNEY="$lockdir/britney.lock"
448
449 lockfile -l 3600 "${LOCK_DAILY}"
450 trap cleanup EXIT ERR TERM HUP INT QUIT
451
452 touch "${LOCK_BRITNEY}"
453
454 GO=(
455     FUNC="notice"
456     TIME=""
457     ARGS=""
458     ERR="false"
459 )
460 stage $GO
461
462 GO=(
463     FUNC="merkel1"
464     TIME="init"
465     ARGS=""
466     ERR="false"
467 )
468 stage $GO
469
470 GO=(
471     FUNC="pgdump_pre"
472     TIME="pg_dump1"
473     ARGS=""
474     ERR=""
475 )
476 stage $GO
477
478 GO=(
479     FUNC="updates"
480     TIME="External Updates"
481     ARGS=""
482     ERR="false"
483 )
484 stage $GO
485
486 GO=(
487     FUNC="punew"
488     TIME="p-u-new"
489     ARGS="p-u-new"
490     ERR=""
491 )
492 stage $GO
493
494 GO=(
495     FUNC="opunew"
496     TIME="o-p-u-new"
497     ARGS="o-p-u-new"
498     ERR=""
499 )
500 stage $GO
501
502 GO=(
503     FUNC="i18n1"
504     TIME="i18n 1"
505     ARGS=""
506     ERR="false"
507 )
508 stage $GO
509
510 lockfile "$LOCK_ACCEPTED"
511
512 GO=(
513     FUNC="accepted"
514     TIME="accepted"
515     ARGS=""
516     ERR=""
517 )
518 stage $GO
519
520 GO=(
521     FUNC="cruft"
522     TIME="cruft"
523     ARGS=""
524     ERR=""
525 )
526 stage $GO
527
528 rm -f $LOCKAC
529
530 GO=(
531     FUNC="msfl"
532     TIME="make-suite-file-list"
533     ARGS=""
534     ERR=""
535 )
536 stage $GO
537
538 GO=(
539     FUNC="fingerprints"
540     TIME="import-keyring"
541     ARGS=""
542     ERR="false"
543 )
544 stage $GO
545
546 GO=(
547     FUNC="overrides"
548     TIME="overrides"
549     ARGS=""
550     ERR=""
551 )
552 stage $GO
553
554 GO=(
555     FUNC="mpfm"
556     TIME="pkg-file-mapping"
557     ARGS=""
558     ERR="false"
559 )
560 stage $GO
561
562 GO=(
563     FUNC="packages"
564     TIME="apt-ftparchive"
565     ARGS=""
566     ERR=""
567 )
568 stage $GO
569
570 GO=(
571     FUNC="pdiff"
572     TIME="pdiff"
573     ARGS=""
574     ERR=""
575 )
576 stage $GO
577
578 GO=(
579     FUNC="release"
580     TIME="release files"
581     ARGS=""
582     ERR=""
583 )
584 stage $GO
585
586 GO=(
587     FUNC="dakcleanup"
588     TIME="cleanup"
589     ARGS=""
590     ERR=""
591 )
592 stage $GO
593
594 GO=(
595     FUNC="buildd"
596     TIME="buildd"
597     ARGS=""
598     ERR=""
599 )
600 stage $GO
601
602 GO=(
603     FUNC="scripts"
604     TIME="scripts"
605     ARGS=""
606     ERR=""
607 )
608 stage $GO
609
610 GO=(
611     FUNC="mirror"
612     TIME="mirror hardlinks"
613     ARGS=""
614     ERR=""
615 )
616 stage $GO
617
618 GO=(
619     FUNC="wb"
620     TIME="w-b"
621     ARGS=""
622     ERR=""
623 )
624 stage $GO
625
626 rm -f "${NOTICE}"
627 rm -f "${LOCK_DAILY}"
628
629 ts "locked part finished"
630
631 GO=(
632     FUNC="pgdump_post"
633     TIME="pg_dump2"
634     ARGS=""
635     ERR=""
636 )
637 stage $GO
638
639 GO=(
640     FUNC="expire"
641     TIME="expire_dumps"
642     ARGS=""
643     ERR=""
644 )
645 stage $GO
646
647 GO=(
648     FUNC="reports"
649     TIME="reports"
650     ARGS=""
651     ERR=""
652 )
653 stage $GO
654
655 GO=(
656     FUNC="dm"
657     TIME=""
658     ARGS=""
659     ERR=""
660 )
661 stage $GO
662
663 GO=(
664     FUNC="bts"
665     TIME=""
666     ARGS=""
667     ERR=""
668 )
669 stage $GO
670
671 GO=(
672     FUNC="merkel2"
673     TIME="merkel projectb push"
674     ARGS=""
675     ERR="false"
676 )
677 stage $GO
678
679 ulimit -m 90000 -d 90000 -s 10000 -v 200000
680
681 GO=(
682     FUNC="runparts"
683     TIME="run-parts"
684     ARGS=""
685     ERR="false"
686 )
687 stage $GO
688
689 GO=(
690     FUNC="i18n2"
691     TIME="i18n 2"
692     ARGS=""
693     ERR="false"
694 )
695 stage $GO
696
697 GO=(
698     FUNC="stats"
699     TIME="stats"
700     ARGS=""
701     ERR="false"
702 )
703 stage $GO
704
705 rm -f ${BRITNEYLOCK}
706
707 GO=(
708     FUNC="aptftpcleanup"
709     TIME="apt-ftparchive cleanup"
710     ARGS=""
711     ERR=""
712 )
713 stage $GO
714
715 GO=(
716     FUNC="compress"
717     TIME="compress"
718     ARGS=""
719     ERR=""
720 )
721 stage $GO
722
723 log "Daily cron scripts successful, all done"
724
725 exec > /dev/null 2>&1
726
727 GO=(
728     FUNC="logstats"
729     TIME=""
730     ARGS=""
731     ERR=""
732 )
733 stage $GO
734
735 cat "$LOGFILE" | mail -s "Log for dinstall run of ${NOW}" cron@ftp-master.debian.org
736
737 # Now, at the very (successful) end of dinstall, make sure we remove
738 # our stage files, so the next dinstall run will do it all again.
739 rm -f "${stagedir}/*"