common 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. # -*- mode:sh -*-
  2. # log something (basically echo it together with a timestamp)
  3. #
  4. # Set $PROGRAM to a string to have it added to the output.
  5. function log () {
  6. local prefix=${PROGRAM:-}
  7. echo "$(date +"%b %d %H:%M:%S") ${HOSTNAME} ${prefix}[$$]: $*"
  8. }
  9. # log the message using log() but then also send a mail
  10. # to the address configured in MAILTO (if non-empty)
  11. function log_error () {
  12. log "$@"
  13. if [[ -z ${MAILTO} ]]; then
  14. echo "$*" | mail -a "X-Debian: DAK" -e -s "[$PROGRAM@${HOSTNAME}] ERROR [$$]" -a "From: Debian FTP Masters <ftpmaster@ftp-master.debian.org>" ${MAILTO}
  15. fi
  16. }
  17. # debug log, only output when DEBUG=1
  18. function debug () {
  19. if [[ $DEBUG -eq 1 ]]; then
  20. log "$*"
  21. fi
  22. }
  23. # Get a tempfile, add it to the right variable to get rid of it,
  24. # and return it
  25. function gettempfile() {
  26. local MAKEDIR=${1:-false}
  27. local TMPARGS=""
  28. if [[ ${MAKEDIR} == true ]]; then
  29. TMPARGS="--directory"
  30. fi
  31. local TMPFILE=$( mktemp -p ${TMPDIR} ${TMPARGS} )
  32. TMPFILES="${TEMPFILES} ${TMPFILE}"
  33. echo "${TMPFILE}"
  34. }
  35. # Function that only cleans tempfiles, but does not exit or otherwise
  36. # care about any exit status
  37. function cleantempfiles() {
  38. resolvetmpfiles
  39. for TEMPFILE in $TMPFILES; do
  40. if [[ -n ${TEMPFILE} ]] && [[ -f ${TEMPFILE} ]]; then
  41. rm -f "${TEMPFILE}"
  42. elif [[ -n ${TEMPFILE} ]] && [[ -d ${TEMPFILE} ]]; then
  43. if [[ ${TEMPFILE} != / ]] && [[ ${TEMPFILE} != /* ]]; then
  44. rm -rf "${TEMPFILE}"
  45. fi
  46. fi
  47. done
  48. TMPFILES=""
  49. }
  50. function resolvetmpfiles() {
  51. # If you don't understand this better not touch the script
  52. for TEMPFILE in $TEMPFILES; do
  53. TMPFILES="${TMPFILES} ${!TEMPFILE:-""}"
  54. done
  55. TEMPFILES=""
  56. }
  57. # Function cleanup
  58. # No arguments
  59. # Cleans up any known tempfile.
  60. # Just ensure your script sets the variable
  61. # TEMPFILES to the names of variables of tempfiles
  62. # Or TMPFILES to the pathes of tempfiles
  63. function cleanup() {
  64. ERRVAL=$?
  65. trap - ERR EXIT TERM HUP INT QUIT
  66. cleantempfiles
  67. return $ERRVAL
  68. }
  69. TEMPFILES=${TEMPFILES:-""}
  70. TMPFILES=${TMPFILES:-""}
  71. # Timestamp. Used for dinstall stat graphs
  72. function log_timestamp() {
  73. echo "Archive maintenance timestamp ($1): $(date +%H:%M:%S)"
  74. }
  75. ########################################################################
  76. ########################################################################
  77. # used by cron.dinstall *and* cron.unchecked.
  78. function make_buildd_dir () {
  79. local archive=$1
  80. # We generate straight into the static mirror location for incoming
  81. log "Preparing buildd area"
  82. dak manage-build-queues -a
  83. dak generate-packages-sources2 -a build-queues
  84. dak generate-releases -a build-queues >/dev/null
  85. if [[ $archive = security ]]; then
  86. ${scriptsdir}/update-buildd-archive ${base}/build-queues ${incoming}/debian-security-buildd
  87. $configdir/cron.buildd
  88. sudo -u archvsync runmirrors -a security-buildd-pool
  89. else
  90. # Stick a last modified date in the page footer
  91. echo "<p>Last updated: $(date -u)</p>" > ${incoming}/web/README.html
  92. write_project_trace "${incoming}/web/debian-buildd"
  93. # Tell the mirrors that we've updated
  94. log "Pushing static for incoming.d.o"
  95. sudo -u archvsync runmirrors -a buildd > ~dak/runmirrors-buildd.log 2>&1 &
  96. chronic timeout -k 600 480 /usr/local/bin/static-update-component incoming.debian.org < /dev/null
  97. wait
  98. fi
  99. }
  100. # Process (oldstable)-proposed-updates "NEW" queue
  101. function punew_do() {
  102. local queue="$1"
  103. local qdir="$2"
  104. local to="${3}"
  105. date -u -R >> REPORT
  106. dak process-policy "${queue}" | tee -a REPORT | mail -a "X-Debian: DAK" -e -s "NEW changes in ${queue}" -a "From: Debian FTP Masters <ftpmaster@ftp-master.debian.org>" "${to}"
  107. echo >> REPORT
  108. dak generate-packages-sources2 -s "${queue}"
  109. STAMP=${STAMP:-$(date "+%Y%m%d%H%M")}
  110. local ppexportdir="${qdir}/tree/${STAMP}"
  111. local targetdir="${qdir}/export"
  112. mkdir -p -- ${ppexportdir}
  113. dak export -q "${queue}" -d "${ppexportdir}" --all
  114. ln -sfT ${ppexportdir} ${targetdir}
  115. find "${qdir}/tree" -mindepth 1 -maxdepth 1 -not -name "${STAMP}" -type d -print0 | xargs --no-run-if-empty -0 rm -rf
  116. }
  117. # These versions used in dinstall
  118. function punew() {
  119. log "Doing automated p-u-new processing"
  120. cd "${queuedir}/p-u-new"
  121. punew_do "$1" "${queuedir}/p-u-new" "debian-release@lists.debian.org"
  122. }
  123. function opunew() {
  124. log "Doing automated o-p-u-new processing"
  125. cd "${queuedir}/o-p-u-new"
  126. punew_do "$1" "${queuedir}/o-p-u-new" "debian-release@lists.debian.org"
  127. }
  128. function backports_policy() {
  129. local queue="backports-policy"
  130. local qdir="/srv/backports-master.debian.org/queue/policy"
  131. local to="backports-team@debian.org"
  132. log "Doing automated ${queue} processing"
  133. cd "${qdir}"
  134. punew_do "${queue}" "${qdir}" "${to}"
  135. }
  136. # Do the unchecked processing, in case we have files.
  137. function do_unchecked () {
  138. cd $unchecked
  139. changes=$(find . -maxdepth 1 -mindepth 1 -type f \( -name \*.changes -o -name \*.dak-commands \) | sed -e "s,./,," | xargs)
  140. report=${queuedir}/REPORT
  141. timestamp=$(date "+%Y-%m-%d %H:%M")
  142. if [[ -n ${changes} ]]; then
  143. log "Processing files ${changes}"
  144. {
  145. echo "${timestamp}: ${changes}"
  146. dak process-upload -a -d "$unchecked"
  147. dak process-commands -d "$unchecked"
  148. } >> ${report}
  149. dak manage-external-signature-requests
  150. else
  151. log "Nothing to do"
  152. echo "Nothing to do" >> ${report}
  153. fi
  154. }
  155. function trigger_wb() {
  156. SSHOPT="-n -o BatchMode=yes -o ConnectTimeout=30 -o SetupTimeout=240"
  157. ssh -q -q ${SSHOPT} wbadm@buildd /srv/wanna-build/trigger.often
  158. }
  159. # process NEW policy queue
  160. function do_new () {
  161. log "Doing NEW processing"
  162. (dak process-policy new; dak process-policy byhand) | mail -a "X-Debian: DAK" -e -s "NEW and BYHAND processing" -a "From: Debian FTP Masters <ftpmaster@ftp-master.debian.org>" ftpmaster@ftp-master.debian.org
  163. log "Processing Backports NEW"
  164. dak process-policy backports-new | mail -a "X-Debian: DAK" -e -s "NEW processing for backports-new" -a "From: Debian FTP Masters <ftpmaster@ftp-master.debian.org>" backports-team@debian.org
  165. log "Cleanup NEW/Backports NEW"
  166. dak clean-suites -a new,backports-new
  167. }
  168. function sync_debbugs () {
  169. # sync with debbugs
  170. log "Sync debbugs version tracking information"
  171. timestamp=$(date "+%Y-%m-%d-%H:%M")
  172. mkdir -p $queuedir/bts_version_track_archive/${timestamp}
  173. rsync -aq $queuedir/bts_version_track/ $queuedir/bts_version_track_archive/${timestamp}
  174. rmdir --ignore-fail-on-non-empty $queuedir/bts_version_track_archive/${timestamp} # remove if empty.
  175. rsync -aq -e "ssh -o Batchmode=yes -o ConnectTimeout=30 -o SetupTimeout=30" --remove-source-files $queuedir/bts_version_track/ bugs-sync:/srv/bugs.debian.org/versions/queue/ftp-master/ 2>/dev/null && touch $lockdir/synced_bts_version || true
  176. NOW=$(date +%s)
  177. TSTAMP=$(stat -c %Y $lockdir/synced_bts_version)
  178. DIFF=$(( NOW - TSTAMP ))
  179. if [[ $DIFF -ge 259200 ]]; then
  180. log_error "Kids, you tried your best and you failed miserably. The lesson is, never try. (Homer Simpson)"
  181. fi
  182. }
  183. function clean_debbugs () {
  184. log "Cleanup debbugs"
  185. # Delete files older than 60 days
  186. find $queuedir/bts_version_track_archive/ -mtime +60 -type f -delete
  187. # Delete empty directories
  188. find $queuedir/bts_version_track_archive/ -empty -type d -delete
  189. }
  190. function reports() {
  191. # Send a report on NEW/BYHAND packages
  192. log "Nagging ftpteam about NEW/BYHAND packages"
  193. dak queue-report | mail -a "X-Debian: DAK" -e -s "NEW and BYHAND on $(date +%D)" -a "From: Debian FTP Masters <ftpmaster@ftp-master.debian.org>" ftpmaster@ftp-master.debian.org
  194. dak queue-report -d backports-new,backports-policy | mail -a "X-Debian: DAK" -e -s "NEW and POLICY on $(date +%D)" -a "From: Debian FTP Masters <ftpmaster@ftp-master.debian.org>" backports-team@debian.org
  195. # and one on crufty packages
  196. log "Sending information about crufty packages"
  197. dak cruft-report -R > $webdir/cruft-report-daily.txt.new
  198. dak cruft-report -R -s experimental >> $webdir/cruft-report-daily.txt.new
  199. echo "Page generated on $(date -u)" >> $webdir/cruft-report-daily.txt.new
  200. mv $webdir/cruft-report-daily.txt.new $webdir/cruft-report-daily.txt
  201. mail -a "X-Debian: DAK" -e -s "Debian archive cruft report for $(date +%D)" -a "From: Debian FTP Masters <ftpmaster@ftp-master.debian.org>" ftpmaster@ftp-master.debian.org < $webdir/cruft-report-daily.txt
  202. }
  203. function pg_timestamp() {
  204. tsname=${1:-"unknown"}
  205. log "Saving postgres transaction id for ${tsname}"
  206. psql -tAc 'select txid_current();' > $base/backup/txid_${tsname}_$(date +%Y.%m.%d-%H:%M:%S)
  207. }
  208. function get_archiveroot() {
  209. local archivename="$1"
  210. local query="SELECT path FROM archive WHERE name='${archivename}'"
  211. local archiveroot="$(psql -tAc "${query}")"
  212. if [[ -z ${archiveroot} ]]; then
  213. echo "get_archiveroot: couldn't get archiveroot for '${archivename}'" >&2
  214. return 1
  215. fi
  216. echo "${archiveroot}"
  217. }
  218. # Cleanup policy queues
  219. function cleanpolicy() {
  220. dak clean-suites -a backports-policy,policy
  221. }
  222. # Scan new packages for contents
  223. function scancontents() {
  224. dak contents -l 10000 scan-binary
  225. dak contents -l 1000 scan-source
  226. }
  227. function ddaccess() {
  228. # Tell our dd accessible mirror to sync itself up.
  229. log "Trigger dd accessible parts sync"
  230. ${scriptsdir}/sync-dd dd-sync dd-sync1 dd-sync2 sync
  231. }
  232. # Write ${path}/project/trace for given path
  233. # Note: use `write_project_trace` which sets version and date variables
  234. function write_project_trace1() {
  235. local path="${1}"
  236. local tracedir="${path}/project/trace"
  237. local TRACEFILE="${tracedir}/${functionname}"
  238. local TRACEFILE_MASTER="${tracedir}/master"
  239. local HIERFILE="${tracedir}/_hierarchy"
  240. mkdir -p -- "${tracedir}"
  241. local DATE_SERIAL=$(date +"%Y%m%d01")
  242. local FILESOAPLUS1=$(awk '/serial/ { print $3+1 }' ${TRACEFILE} || echo ${DATE_SERIAL} )
  243. local SERIAL
  244. if [[ ${DATE_SERIAL} -gt ${FILESOAPLUS1} ]]; then
  245. SERIAL="${DATE_SERIAL}"
  246. else
  247. SERIAL="${FILESOAPLUS1}"
  248. fi
  249. cat <<EOF > ${TRACEFILE}
  250. ${DATE}
  251. Creator: dak ${CREATOR_VERSION}
  252. Running on host: ${HOST}
  253. Archive serial: ${SERIAL}
  254. Date: ${RFC822DATE}
  255. Architectures: ${archs%* } source
  256. EOF
  257. cat <<EOF > ${HIERFILE}
  258. ${functionname} ${functionname} ${HOST} ${HOST}
  259. EOF
  260. cp ${HIERFILE} ${HIERFILE}.mirror
  261. # Now make it accessible via one name, no matter on which host we run
  262. ln -sf $(basename ${TRACEFILE}) ${TRACEFILE_MASTER}
  263. }
  264. # Write ${path}/project/trace for given paths
  265. function write_project_trace() {
  266. cd ${configdir}
  267. local CREATOR_VERSION="g$(git rev-parse --short HEAD)"
  268. local DATE=$(LC_ALL=POSIX LANG=POSIX date -u)
  269. local RFC822DATE=$(LC_ALL=POSIX LANG=POSIX date -u -R)
  270. local HOST=$(hostname -f)
  271. local path
  272. for path in "${@}"; do
  273. write_project_trace1 "${path}"
  274. done
  275. }
  276. function fingerprints() {
  277. log "Updating fingerprints"
  278. local todo=${1:-all}
  279. dak import-keyring -L /srv/keyring.debian.org/keyrings/debian-keyring.gpg
  280. if [[ ${todo} == all ]]; then
  281. dak import-keyring -L /srv/keyring.debian.org/keyrings/debian-nonupload.gpg
  282. OUTFILE=$( gettempfile )
  283. dak import-keyring --generate-users "%s" /srv/keyring.debian.org/keyrings/debian-maintainers.gpg >"${OUTFILE}"
  284. if [[ -s ${OUTFILE} ]]; then
  285. /usr/sbin/sendmail -odq -oi -t -f envelope@ftp-master.debian.org <<EOF
  286. From: Debian FTP Masters <ftpmaster@ftp-master.debian.org>
  287. To: <debian-project@lists.debian.org>
  288. Subject: Debian Maintainers Keyring changes
  289. Content-Type: text/plain; charset=utf-8
  290. X-Debian: DAK
  291. MIME-Version: 1.0
  292. The following changes to the debian-maintainers keyring have just been activated:
  293. $(cat $OUTFILE)
  294. Debian distribution maintenance software,
  295. on behalf of the Keyring maintainers
  296. EOF
  297. fi
  298. rm -f "$OUTFILE"
  299. fi
  300. }
  301. function dakcleanup() {
  302. log "Cleanup old packages/files"
  303. local queuevarnames=${1:-unchecked}
  304. dak clean-suites -m 10000
  305. for queue in ${queuevarnames}; do
  306. dak clean-queues -i ${!queue}
  307. done
  308. }
  309. function mklslar() {
  310. local archiveroot
  311. local FILENAME=ls-lR
  312. for archive in "${public_archives[@]}"; do
  313. archiveroot="$(get_archiveroot "${archive}")"
  314. cd "${archiveroot}"
  315. log "Removing any core files ..."
  316. find -type f -name core -print -delete
  317. log "Checking symlinks ..."
  318. symlinks -rd .
  319. log "Creating recursive directory listing ... "
  320. rm -f ${FILENAME}.gz
  321. TZ=UTC ls -lR | gzip -9c --rsyncable --no-name > ${FILENAME}.gz
  322. done
  323. }
  324. function linkmorgue() {
  325. ${scriptsdir}/link_morgue.sh
  326. }
  327. function fetchqueuedpackages() {
  328. local host=$1
  329. # Sync new uploaded packages from the central upload queue host.
  330. log "Sync new uploads from upload queues"
  331. cd ${unchecked}
  332. rsync -rtq --safe-links --chmod=F640,D755 --remove-source-files $1:/does/not/matter . || true
  333. }
  334. ########################################################################
  335. ########################################################################
  336. ########################################################################
  337. ########################################################################
  338. # Function to save which stage we are in, so we can restart an interrupted
  339. # dinstall. Or even run actions in parallel, if we dare to, by simply
  340. # backgrounding the call to this function. But that should only really be
  341. # done for things we don't care much about.
  342. #
  343. # This should be called with the first argument being an array, with the
  344. # members
  345. # - FUNC - the function name to call
  346. # - ARGS - Possible arguments to hand to the function. Can be the empty string
  347. # - TIME - The timestamp name. Can be the empty string
  348. # - ERR - if this is the string false, then the call will be surrounded by
  349. # set +e ... set -e calls, so errors in the function do not exit
  350. # dinstall. Can be the empty string, meaning true.
  351. #
  352. # MAKE SURE TO KEEP THIS THE LAST FUNCTION, AFTER ALL THE VARIOUS ONES
  353. # ADDED FOR DINSTALL FEATURES!
  354. function stage() {
  355. ARGS='GO[@]'
  356. local "${!ARGS}"
  357. local error=${ERR:-"true"}
  358. ARGS=${ARGS:-""}
  359. log "########## ${PROGRAM} BEGIN: ${FUNC} ${ARGS} ##########"
  360. local STAGEFILE="${stagedir}/${FUNC}${ARGS:+_}${ARGS}"
  361. STAGEFILE=${STAGEFILE// /_}
  362. if [[ -f ${STAGEFILE} ]]; then
  363. local stamptime=$(/usr/bin/stat -c %Z "${STAGEFILE}")
  364. local unixtime=$(date +%s)
  365. local difference=$(( unixtime - stamptime ))
  366. if [[ ${difference} -ge 14400 ]]; then
  367. log_error "Did already run ${FUNC}, stagefile exists, but that was ${difference} seconds ago. Please check."
  368. else
  369. log "Did already run ${FUNC}, not calling again..."
  370. fi
  371. return
  372. fi
  373. debug "Now calling function ${FUNC}. Arguments: ${ARGS}. Timestamp: ${TIME}"
  374. # Make sure we are always at the same place. If a function wants
  375. # to be elsewhere, it has to cd first!
  376. cd ${configdir}
  377. if [[ -f ${LOCK_STOP} ]]; then
  378. log "${LOCK_STOP} exists, exiting immediately"
  379. exit 42
  380. fi
  381. # Do we care about trouble in the function we call?
  382. if [[ ${error} == false ]]; then
  383. set +e
  384. fi
  385. # Now redirect the output into $STAGEFILE.log. In case it errors
  386. # out somewhere our errorhandler trap can then mail the contents
  387. # of $STAGEFILE.log only, instead of a whole ${PROGRAM} logfile.
  388. # Short error mails ftw!
  389. if [[ ${TIMESTAMP} == true ]]; then
  390. ${FUNC} ${ARGS} 2>&1 | tee -a "${STAGEFILE}.log" | ts "%b %d %H:%M:%S ${HOSTNAME} ${PROGRAM}[$$]: ${FUNC} "
  391. else
  392. ${FUNC} ${ARGS} 2>&1 | tee -a "${STAGEFILE}.log"
  393. fi
  394. # No matter what happened in the function, we make sure we have
  395. # set -e default state back
  396. set -e
  397. # Make sure we are always at the same place.
  398. cd ${configdir}
  399. # We always use the same umask. If a function wants to do
  400. # different, fine, but we reset.
  401. umask 022
  402. touch "${STAGEFILE}"
  403. if [[ -n ${TIME} ]]; then
  404. log_timestamp "${TIME}"
  405. fi
  406. rm -f "${STAGEFILE}.log"
  407. log "########## ${PROGRAM} END: ${FUNC} ##########"
  408. if [[ -f ${LOCK_STOP} ]]; then
  409. log "${LOCK_STOP} exists, exiting immediately"
  410. exit 42
  411. fi
  412. }