common 16 KB

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