61b7a6359d1f5bd189989d845f75d54aae637ab2
[mom.git] / pl_mop.sh
1 #!/bin/bash
2 #
3 # Runs once a day to "fix" nodes in various ways
4 #
5 # Mark Huang <mlhuang@cs.princeton.edu>
6 # Copyright (C) 2005 The Trustees of Princeton University
7 #
8 # $Id: pl_mop.sh,v 1.6 2006/04/28 19:28:59 mlhuang Exp $
9 #
10
11 PATH=/sbin:/usr/sbin:$PATH
12
13 # Parse PLC configuration
14 if [ -r /etc/planetlab/plc_config ] ; then
15     . /etc/planetlab/plc_config
16 else
17     PLC_SLICE_PREFIX="pl"
18 fi
19
20 PIDFILE=/var/run/pl_mop.pid
21
22 # Record PID
23 if [ -f $PIDFILE ] ; then
24     if kill -0 `cat $PIDFILE` >/dev/null 2>&1 ; then
25         logger -p info -t pl_mom "$0 (`cat $PIDFILE`) already running"
26         exit 1
27     fi
28 fi
29 echo $$ > $PIDFILE
30
31 # Clean up stale lock files
32 trap "rm -f $PIDFILE" EXIT
33
34 # Run a command and log its output to syslog
35 run() {
36     eval $* 2>&1 | logger -p info -t "pl_mom: $1"
37 }
38
39 # OpenSSH server 3.8 and above refuse login for "locked"
40 # accounts. Replace "!!" with "*" in /etc/shadow for all VServer
41 # accounts.
42 fix_etc_shadow() {
43     echo "* Fixing /etc/shadow"
44
45     shopt -s nullglob
46     for file in /etc/vservers/*.conf pl_admin.conf site_admin.conf ; do
47         slice=$(basename ${file%*.conf})
48         if grep -q "$slice:\!\!" /etc/shadow ; then
49             sed -i -e "s/$slice:\!\!:\(.*\)/$slice:*:\1/" /etc/shadow
50         fi
51     done
52 }
53
54 # keep essential services running
55 restart_services() {
56     for service in sshd pl_sshd swapmon pl_nm proper ; do
57         echo "* Checking $service"
58         status=$(service $service status)
59         if [ $? -ne 0 ] || echo $status 2>&1 | grep -q stopped ; then
60             echo "* Restarting $service"
61             service $service start
62         fi
63     done
64 }
65
66 # keep netflow running
67 restart_netflow() {
68     echo "* Checking netflow"
69     echo "sudo /sbin/service netflow restart" | su - pl_netflow
70     if [ $? -ne 0 ] ; then
71         echo "* Restarting netflow"
72         service netflow-init start
73         vserver pl_netflow start
74         echo "sudo /sbin/service netflow restart" | su - pl_netflow
75     fi
76 }
77
78 # keep pl_conf running
79 restart_pl_conf() {
80     echo "* Checking pl_conf"
81     vserver pl_conf exec /sbin/service pl_conf status >/dev/null 2>&1
82     if [ $? -ne 0 ] ; then
83         echo "* Restarting pl_conf"
84         vserver pl_conf stop
85         vserver pl_conf start
86     fi
87 }
88
89 # GPG keys are installed in /etc/pki/rpm-gpg by both the Boot Manager
90 # during initial installation, and by PlanetLabConf during daily
91 # updates. NodeUpdate imports the keys into the RPM database before
92 # running yum daily. vserver-reference copies and imports the keys
93 # into the reference images and system slices daily. The only parts of
94 # this process that are actually necessary, are the Boot Manager and
95 # vserver-reference. However, we do not want to force a re-install of
96 # all nodes, and we do not want to force an update of
97 # vserver-reference, so in the meantime, PlanetLabConf and NodeUpdate
98 # take care of getting the keys installed and imported in /, and this
99 # script takes care of getting them installed in the reference images
100 # and system slices, until we can get a new vserver-reference image
101 # pushed out.
102 update_vserver_reference() {
103     echo "* Updating VServer reference"
104
105     shopt -s nullglob
106
107     VROOTS="/vservers/vserver-reference /vservers/.vcache/* /vservers/${PLC_SLICE_PREFIX}_*"
108
109     # Copy configuration files from host to slices
110     for file in \
111         /etc/hosts /etc/resolv.conf /etc/yum.conf /etc/planetlab/node_id \
112         /etc/planetlab/plc_config* /etc/planetlab/php/* \
113         /etc/pki/rpm-gpg/* ; do
114       if [ -r $file ] ; then
115           for vroot in $VROOTS ; do
116               install -D -m 644 $file $vroot/$file
117           done
118       fi
119     done
120
121     # (Re)install GPG signing keys
122     if [ -d /etc/pki/rpm-gpg ] ; then
123         for vroot in $VROOTS ; do
124             chroot $vroot rpm --allmatches -e gpg-pubkey || :
125             chroot $vroot rpm --import /etc/pki/rpm-gpg/* || :
126         done
127     fi
128 }    
129
130 # kill all the processes running in slice contexts
131 vkillall() {
132     vps -A | awk '(int($2) > 1) { system("vkill -c " $2 " -s 9 " $1); }'
133     # unmounts all the /proc and /dev/pts mounts in each vserver
134     tries=10
135     while grep -q /vservers/ /proc/mounts && [ $tries -gt 0 ] ; do
136         tries=$(($tries -1))
137         # arizona_stork seems to generate some weird mount points of the form
138         # /vservers/arizona_stork/tmp/0.886421543959\040(deleted) that should be
139         # /vservers/arizona_stork/tmp/0.886421543959
140         awk '(/vservers\//) { sub(/\\040.*$/, ""); print "Unmounting " $2; system("umount " $2); }' /proc/mounts
141     done
142 }   
143
144 # /vservers gets re-mounted read-only by the kernel if an ext3 journal
145 # transaction aborts
146 fix_vservers() {
147     echo "* Fixing /vservers"
148
149     # test to see if /vservers is mounted read-only
150     mkdir -p /vservers/.vtmp
151     tmp=$(mktemp /vservers/.vtmp/fixit.XXXXXX)
152     if [ $? -eq 0 ] ; then
153         rm -f $tmp
154         return 0
155     fi
156
157     # kill all processes running in slice contexts
158     vkillall
159
160     # stop vcached
161     pidfile=/var/run/vcached.pid
162     if [ -r "$pidfile" ] ; then
163         kill $(cat $pidfile)
164     fi
165     touch $pidfile
166
167     # unmounts /vservers
168     if umount /vservers ; then
169         # install expect if necessary
170         if ! rpm -q expect ; then
171             yum -y install expect
172         fi
173
174         # tell expect to hit the 'y' key every time fsck asks
175         expect -c 'set timeout 3600; spawn fsck /dev/mapper/planetlab-vservers; expect "<y>?" { send "y\r"; exp_continue }'
176
177         # blow away the vserver cache
178         rm -rf /vservers/.vcache/*
179
180         # XXX re-mount /vservers
181         # mount /vservers
182
183         # shutdown instead to avoid clearing disk quotas
184         shutdown -r now "/vservers filesystem repaired, rebooting"
185     else
186         echo "Unable to unmount /vservers!" >&2
187     fi
188
189     # allow vcached to run again
190     rm -f $pidfile
191 }
192
193 kill_duplicate_ssh() {
194     echo "* Killing stale duplicate SSH instances"
195
196     # count the number of SSH instances started by each slice
197     ps -C sshd -o command= |
198     grep " \[priv\]" |
199     sort | uniq -c |
200     while read instances sshd slice priv ; do
201         # kill all old instances
202         if [ $instances -gt 10 ] ; then
203             ps -C sshd -o pid=,start_time=,command= |
204             grep "$slice \[priv\]" |
205             while read pid start_time command ; do
206                 start_time=$(date -d "$start_time" +%s)
207                 min=$(date -d "6 hours ago" +%s)
208                 if [ $start_time -lt $min ] ; then
209                     echo "* Killing $slice sshd pid $pid"
210                     kill -9 $pid
211                 fi
212             done
213         fi
214     done
215 }
216
217 # XXX kill zombie slices
218
219 # XXX reboot if boot state changes
220
221 run fix_vservers
222
223 run fix_etc_shadow
224
225 run restart_services
226
227 run restart_pl_conf
228
229 run restart_netflow
230
231 run kill_duplicate_ssh
232
233 run update_vserver_reference