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