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

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