source: trunk/debathena/config/auto-update/debian/athena-auto-update @ 25621

Revision 25621, 10.5 KB checked in by kaduk, 12 years ago (diff)
Emit proper comment string for apt.conf files
RevLine 
[23143]1#!/bin/sh
2
[23156]3complain() {
[24385]4  logger -t "athena-auto-update" -p user.notice "$*"
[24376]5  updstatus="failed"
6  updmsg="$*"
[23156]7}
8
[25274]9# NOTE: Unlike complain(), calling warn() without subsequently
10#       calling "exit" is not supported and its behavior is undefined
[25043]11warn() {
12  # If we've already had a warning once, then fail
13  if [ "$updstatus" = "warning" ]; then
14      complain "$*"
15  else
16      updstatus="warning"
17      updmsg="$*"
18  fi
19}
20
[24376]21save_success() {
[25273]22  # We used to check for 'warning' here for non-fatal warnings.
23  # There is no longer any such thing.
24  updstatus="ok"
25  updmsg="$*"
[24376]26}
27
28save_state() {
29  rm -f $statfile
[24522]30  echo "$updlast|$(date +"%s")|$updstatus|$updmsg" > $statfile
[24376]31
32
[23156]33maybe_reboot() {
[25080]34  if [ "$SKIP_REBOOT" = "y" ]; then
[24394]35      return
36  fi
[23156]37  if [ -f /var/run/reboot-required ]; then
38    # A package wants us to reboot the machine.  Do so if no one is
39    # logged in.  Be paranoid about stale utmp entries.
40    ttys=$(w -h -s | awk '{print $2}')
41    for tty in $ttys; do
42      pids=$(ps --no-heading -j -t "$tty" 2>/dev/null \
43             | awk '($1 == $3) {print $1}')
44      if [ -n "$pids" ]; then
45        return
46      fi
47    done
48    # screen processes count as logins.
49    if pgrep '^screen' > /dev/null; then
50      return
51    fi
[24376]52    save_state
[23156]53    reboot
54    exit
55  fi
56}
57
[25363]58withtimeout () {
59  if dpkg-query --showformat '${Status}\n' -W timeout 2>/dev/null | grep -q ' installed$'; then
60    # tct timeout
61    timeout 1810 timeout -15 1800 "$@"
62  else
63    # coreutils timeout
64    timeout -k 10s 30m "$@"
65  fi
66}
67
[25043]68SKIP_REBOOT="n"
69DEBUG="n"
70VERBOSE="n"
71while getopts "nvd" opt; do
72    case "$opt" in
73        d) DEBUG="y";;
74        v) VERBOSE="y";;
75        n) SKIP_REBOOT="y";;
76        \?)
77            echo "Usage: $0 [ -d ] [ -n ] [ -v ]"
78            ;;
79    esac
80done
[24394]81
[25043]82[ "$DEBUG" = "y" ] && VERBOSE="y"
83
[23143]84if [ 0 != "$(id -u)" ]; then
85  echo "This script must be run as root." >&2
86  exit 1
87fi
88
[24147]89# Don't run updates during a cluster login.
[25043]90# Unless forced
91if [ -e /var/run/athena-login ] && [ "$DEBUG" != "y" ]; then
[24147]92  exit 0
93fi
94
[23143]95# Avoid confusing the system by running two updates at once.
96pidfile=/var/run/athena-update.pid
97if [ -e $pidfile ]; then
[23148]98  if ! kill -0 "$(cat $pidfile)" 2>/dev/null; then
[23143]99    rm -f $pidfile
100  fi
101fi
102(set -o noclobber; echo $$ > $pidfile) 2>/dev/null || exit
103
[23156]104trap 'rm -f $pidfile' EXIT
[23143]105
[24376]106statfile="/var/lib/athena-update-status"
107updstatus="unknown"
108updmsg=""
[24522]109updlast=$(date +"%s")
[24376]110
111# Get the last successful update
112if [ -f $statfile ]; then
113    updlast=$(awk -F\| '{print $1;}' $statfile)
[25043]114    updstatus=$(awk -F\| '{print $3;}' $statfile)
[24376]115fi
116
[23156]117# Make sure nothing expects input on stdin.
118exec </dev/null
119
[25043]120# Save a reference to STDOUT
121exec 3>&1
122
[23717]123# Redirect further output to a log file.
124exec >>/var/log/athena-update 2>&1
[23156]125
[23717]126# Write a log header now and a footer at exit.
[24147]127# Also write a target for cluster's /etc/nologin symlink.
[23717]128echo "-----"
129echo "** Beginning Athena auto-update at $(date)"
130
[24147]131cat > /var/run/athena-nologin << NOLOGIN
132This system is currently taking software updates.
133Please log in to a different system.
134NOLOGIN
135
[25617]136echo "Inhibiting dpkg-preconfigure to work around aptitude bugs..."
137cat > /etc/apt/apt.conf.d/99debathena-inhibit-preconfigure <<APTCONF
[25621]138// This file should only exist while an auto-update is in progress.
139// It will be removed without notice.  You have been warned.
[25617]140#clear DPkg::Pre-Install-Pkgs;
141APTCONF
142
[23717]143finish() {
144    echo "** Ending Athena auto-update at $(date)"
145    echo "-----"
146    echo
[25618]147    rm -f /etc/apt/apt.conf.d/99debathena-inhibit-preconfigure
[23717]148    rm -f $pidfile
[24147]149    rm -f /var/run/athena-nologin
[24376]150    save_state
[23717]151    exit
152}
153trap finish EXIT
154
155v() {
[25043]156  [ "$VERBOSE" = "y" ] && echo "Running" "$@" >&3
[23717]157  echo "** Running:" "$@"
158  "$@"
159}
160
161
[23786]162# Allow hesiod cluster info to specify the debathena apt release.
[23159]163# (Will do nothing if debathena-clusterinfo isn't installed.)
[23717]164[ -x /usr/sbin/save-cluster-info ] && v /usr/sbin/save-cluster-info
[23159]165cinfo=/var/run/athena-clusterinfo.sh
[23786]166slist=/etc/apt/sources.list.d/debathena.clusterinfo.list
167if [ -r "$cinfo" ] && ( [ ! -e "$slist" ] || [ -w "$slist" ] ); then
168  echo "** Updating debathena.clusterinfo.list"
169  [ -e "$slist" ] && rm "$slist"
170  dsource="$(egrep -h '^deb(-src)? http://debathena\.mit\.edu/apt ' /etc/apt/sources.list /etc/apt/sources.list.d/*.list 2>/dev/null | sort -u)"
171  if [ -n "$dsource" ]; then
172    (. $cinfo
173     echo "# This file is automatically updated by debathena-auto-update"
174     echo "# based on your Hesiod cluster information. If you want to"
175     echo "# make changes, do so in another file."
176     echo
177     case $APT_RELEASE in
178       production)  ;;
[23814]179       proposed)    echo "$dsource" | awk '$3 !~ /-/ {$3 = $3 "-proposed"; print}' ;;
180       development) echo "$dsource" | awk '$3 != /-/ {$3 = $3 "-proposed"; print}'
181                    echo "$dsource" | awk '$3 != /-/ {$3 = $3 "-development"; print}' ;;
[23786]182     esac
183    ) > $slist
184  else
185    echo "Never mind, I can't figure out which sources.list line is Debathena's"
186  fi
187else
188  echo "** Skipping update of debathena.clusterinfo.list"
[23159]189fi
190
[23174]191# Tell apt not to expect user input during package installation.
192export DEBIAN_FRONTEND=noninteractive
193
[25043]194# Set conservative defaults in case file is missing
195UPDATE_FORCE_CONFFILE=old
196RUN_UPDATE_HOOK=no
197# Process defaults file
198[ -f /etc/default/debathena-auto-update ] && . /etc/default/debathena-auto-update
199# On cluster machines, force our desired settings
200# Ignore /etc/default/debathena-auto-update
201if dpkg-query --showformat '${Status}\n' -W "debathena-cluster" 2>/dev/null | grep -q ' installed$'; then
202    UPDATE_FORCE_CONFFILE=new
203    RUN_UPDATE_HOOK=yes
204fi
205
[25052]206UPDATE_HOOK_URL="https://athena10.mit.edu/update-hook/debathena-update-hook.sh"
207UPDATE_HOOK_SUM="https://athena10.mit.edu/update-hook/debathena-update-hook-sha256sum"
208MITCA="/usr/share/debathena-auto-update/mitCA.crt"
209UPDATE_HOOK="/var/run/debathena-update-hook.sh"
[25043]210
211rm -f $UPDATE_HOOK
[25052]212if [ "$RUN_UPDATE_HOOK" = "yes" ] && \
[25043]213   curl -sf -o $UPDATE_HOOK --cacert $MITCA $UPDATE_HOOK_URL; then
214   chmod 500 $UPDATE_HOOK
[25052]215   SHA256SUM="$(curl -sf --cacert $MITCA $UPDATE_HOOK_SUM)"
[25043]216   rv=$?
[25070]217   if [ $rv != 0 ]; then
[25043]218       complain "Failed to retrieve $UPDATE_HOOK_SUM (curl returned $rv)"
219       exit
220   fi
[25070]221   LOCALSUM="$(sha256sum $UPDATE_HOOK | awk '{print $1}')"
222   if [ "$SHA256SUM" != "$LOCALSUM" ]; then
223       complain "bad update hook checksum ($SHA256SUM != $LOCALSUM)"
224       exit
225   fi     
226   if ! [ -f "/var/lib/athena-update-hooks/$SHA256SUM" ]; then
[25090]227       if ! v $UPDATE_HOOK; then
[25070]228           complain "update hook returned non-zero status"
229           exit
230       else
231           touch "/var/lib/athena-update-hooks/$SHA256SUM"
232       fi
233   fi
[25043]234fi
235
236echo "Running aptitude install"
237if ! v aptitude --quiet --assume-yes install; then
238  # Don't fail, because make dpkg --configure -a will save us 
239  echo "ERROR: aptitude install failed, but continuing anyway"
240fi
241 
242
[24337]243# Configure any unconfigured packages (Trac #407)
244if ! v dpkg --configure -a; then
245  complain "Failed to configure unconfigured packages."
246  exit
247fi 
248
249# A recently configured package may want a reboot
[24376]250save_success "Rebooted after dpkg --configure -a"
[24337]251maybe_reboot
252
[25043]253# Ensure that the mirrors aren't broken
254urls=$(cat /etc/apt/sources.list /etc/apt/sources.list.d/*.list | grep -v ^# | grep -v ^$ | awk '{print $2}' | sort | uniq)
255failed=""
256for u in $urls; do
[25064]257    # We don't (yet) know how to verify other URI schemes
258    if ! echo $u | grep -q "^http:"; then
259        continue
260    fi
[25043]261    curl -m 60 -sfL -o /dev/null $u
262    if [ $? != 0 ]; then
263        if [ -z "$failed" ]; then
264            failed=$u
265        else
266            failed="$failed $u"
267        fi
268    fi
269done
270if [ -n "$failed" ]; then
271    warn "Failed to contact mirror(s): $failed"
272    exit
273fi
274
[23156]275# Update the aptitude cache.
[23717]276if ! v aptitude --quiet --assume-yes update; then
[23156]277  complain "aptitude update failed"
278  exit
279fi
280
[25070]281# If new licenses were installed since the last update, deal.
[24980]282licenses=/usr/share/debathena-license-config/debathena-license-selections
[25049]283if [ -f /var/lib/debathena-license-config/reconfigure_required ]; then
[25080]284    rm -f /var/lib/debathena-license-config/reconfigure_required
[25049]285    if [ -f $licenses ]; then
286        for p in $(awk '{print $1}' $licenses); do
287            if dpkg-query --showformat '${Status}\n' -W $p 2>/dev/null | grep -q ' installed$'; then
288                if ! v dpkg-reconfigure -fnoninteractive $p; then
[25070]289                    # Don't fail here
[25049]290                    complain "Failed to dpkg-reconfigure $p"
291                fi
292            fi
293        done
294    else
295        complain "Could not find $licenses"
296        exit
297    fi
298fi
[24980]299
[25049]300
[23156]301# Exit quietly (except for perhaps rebooting) if there are no upgrades
302# to take.
[25070]303pattern='^0 packages upgraded, 0 newly installed, 0 to remove'
[23717]304if v aptitude --simulate --assume-yes full-upgrade | grep -q "$pattern"; then
305  echo "Nothing to do!"
[24376]306  save_success "No updates"
[23156]307  maybe_reboot
308  exit
309fi
310
311# Download packages first.
[25363]312if ! v withtimeout aptitude --quiet --assume-yes --download-only full-upgrade; then
[23156]313  complain "download failed"
314  exit
[23143]315fi
316
[23156]317# If the debathena-reactivate package is installed, call into the
318# login snapshot script to create a root snapshot for the next update.
319if [ -x /usr/sbin/athena-login-snapshot ]; then
320  echo "** Creating root snapshot"
321  /usr/sbin/athena-login-snapshot update-start
322fi
323
[24457]324APTITUDE_OPTS=
[24941]325case $UPDATE_FORCE_CONFFILE in
326    old)
327        APTITUDE_OPTS="-o Dpkg::Options::=--force-confold"
[24966]328        export UCF_FORCE_CONFFOLD=1
[24941]329        ;;
330    new)
331        APTITUDE_OPTS="-o Dpkg::Options::=--force-confnew"
[24966]332        export UCF_FORCE_CONFFNEW=1
[24941]333        ;;
334    *)
335        complain "Invalid value for UPDATE_FORCE_CONFFILE"
336        exit
337        ;;
338esac
339
[24457]340
[23143]341# Perform the update.  In some corner cases, aptitude might decide
342# that the best course of action is to remove the Debathena
343# metapackage, so be paranoid about that.
[23174]344v aptitude --quiet --assume-yes keep-all
[25363]345v withtimeout aptitude --quiet --assume-yes --download-only dist-upgrade
[25278]346if result=$(aptitude -F "%p" search '?action(remove) (^debathena-cluster$ | ^debathena-workstation$ | ^debathena-login$ | ^debathena-standard$ | ^openafs-modules-~D^linux-image-)')
[23250]347  [ -n "$result" ]; then
[23220]348  echo "** metapackages would be removed by the update, aborting:" $result
[23174]349  v aptitude --quiet --assume-yes keep-all
[23220]350  complain "metapackages would be removed by update:" $result
[23250]351elif result=$(aptitude -F "%p" search '~b')
352  [ -n "$result" ]; then
353  echo "** packages would be broken by the update, aborting:" $result
354  v aptitude --quiet --assume-yes keep-all
355  complain "packages would be broken by update:" $result
[23156]356else
[25362]357  if v aptitude $APTITUDE_OPTS --quiet --assume-yes install; then
358    # Successful update, reset $updlast
359    updlast=$(date +"%s")
360    save_success "Successful update"
361  fi
[23143]362fi
363
[23549]364# Finally, update the apt-file cache
365v apt-file update
366
[23156]367if [ -x /usr/sbin/athena-login-snapshot ]; then
368  echo "** Cleaning up root snapshot"
369  /usr/sbin/athena-login-snapshot update-end
370fi
371
372maybe_reboot
[23143]373exit
Note: See TracBrowser for help on using the repository browser.