8c3a77d18afc5da2985a96b52598d4b5265b9bc1
[sysadmin-cookbook] / recepies / lxc / lxc-watchdog.sh
1 #! /bin/sh
2 ### BEGIN INIT INFO
3 # Provides:          lxc-watchdog
4 # Required-Start:    $remote_fs $named $network $time
5 # Required-Stop:     $remote_fs $named $network
6 # Required-Start:    
7 # Required-Stop:     
8 # Default-Start:     2 3 4 5
9 # Default-Stop:      0 1 6
10 # Short-Description: Manage Linux Containers startup/shutdown
11 # Description:       Uses clever inotify hack to monitor container's
12 #                    halt/reboot events watching /var/run/utmp
13 ### END INIT INFO
14
15 # Author: Dobrica Pavlinusic <dpavlin@rot13.org>
16 #
17 # based on Tony Risinger post to lxc-users mailing list
18 # http://www.mail-archive.com/lxc-users@lists.sourceforge.net/msg00074.html
19
20
21 which inotifywait >/dev/null || apt-get install inotify-tools
22
23
24 lxc_exists() {
25         name=$1
26
27         if [ ! -e /var/lib/lxc/$name/config ] ; then
28                 echo "Usage: $0 name"
29                 lxc_status
30                 exit 1
31         fi
32 }
33
34
35 lxc_rootfs() {
36         grep lxc.rootfs "/var/lib/lxc/$1/config" | cut -d= -f2 | sed 's/^ *//'
37 }
38
39
40 lxc_status() {
41         lxc-ls -1 | sort -u | xargs -i lxc-info -n {} | sed "s/'//g" | while read name is status ; do
42                 boot="    "
43                 test -s /var/lib/lxc/$name/on_boot && boot="boot"
44                 echo "$name $status $boot $(lxc_rootfs $name)"
45         done
46 }
47
48
49 cleanup_init_scripts() {
50         rootfs=$(lxc_rootfs $1)
51
52         ls \
53                 $rootfs/etc/rc?.d/*umountfs \
54                 $rootfs/etc/rc?.d/*umountroot \
55                 $rootfs/etc/rc?.d/*hwclock* \
56         2>/dev/null | xargs -i rm -v {}
57 }
58
59
60 setup_inittab() {
61         rootfs=$(lxc_rootfs $1)
62         remove=$2
63         add=$3
64
65         # let container respond to kill -SIGPWR
66         inittab=$rootfs/etc/inittab
67         if ! grep "$add" ${inittab} >/dev/null ; then
68                 grep -v "$remove" ${inittab} > ${inittab}.new
69                 echo $add >> ${inittab}.new
70                 mv ${inittab}.new ${inittab}
71                 echo "$inittab modified with $add"
72         fi
73 }
74
75
76 lxc_log() {
77         echo `date +%Y-%m-%dT%H:%M:%S` $*
78 }
79
80
81 lxc_kill() {
82         name=$1
83         sig=$2
84
85         init_pid=`lxc-ps -C init -o pid | grep "^$name" | cut -d" " -f2-`
86         if [ -z "$init_pid" ] ; then
87                 lxc-info -n $name
88                 exit 1
89         fi
90         lxc_log "$name kill $sig $init_pid"
91         /bin/kill $sig $init_pid
92 }
93
94 lxc_stop() {
95         lxc_log "$name stop"
96         lxc_kill $name -SIGPWR
97         lxc-wait -n $name -s STOPPED
98         lxc_log "$name stoped"
99 #       rm -f /var/lib/lxc/${name}/on_boot
100 }
101
102
103 lxc_start() {
104         name=$1
105
106         if ! lxc-info -n $name | grep RUNNING ; then
107                 lxc_log "$name start"
108                 lxc-start -n $name -o /tmp/${name}.log -d
109                 lxc-wait  -n $name -s RUNNING
110                 lxc-info  -n $name
111                 test -f /var/lib/lxc/${name}/on_boot || echo $name > /var/lib/lxc/${name}/on_boot
112         fi
113 }
114
115 lxc_watchdog() {
116 name=$1
117 rootfs=$(lxc_rootfs $1)
118
119 while true; do
120         vps_utmp=${rootfs}/var/run/utmp
121         tasks=`wc -l < /cgroup/${name}/tasks`
122         test -z "$tasks" && exit 1
123         if [ "$tasks" -eq 1 ]; then
124
125                 runlevel="$(runlevel ${vps_utmp})"
126                 lxc_log "$name runlevel $runlevel"
127
128                 case $runlevel in
129                 N*)
130                         # nothing for new boot state
131                 ;;
132                 ??0)
133                         lxc_log "$name halt"
134                         lxc-stop -n "${name}"
135                         lxc-wait -n ${name} -s STOPPED
136                         break
137                 ;;
138                 ??6)
139                         lxc_log "$name reboot";
140                         lxc-stop -n ${name}
141                         lxc-wait -n ${name} -s STOPPED
142                         lxc-start -d -n ${name} -o /tmp/${name}.log
143                 ;;
144                 *)
145                         # make sure vps is still running
146                         state="$(lxc-info -n "${name}" | sed -e 's/.* is //')"
147                         [ "$state" = "RUNNING" ] || break
148                 ;;
149                 esac
150         else
151                 lxc_log "$name $tasks tasks"
152         fi
153
154         # time of 5 minutes on it JUST IN CASE...
155         inotifywait -qqt 300 ${vps_utmp}
156 done
157
158 lxc_log "$name watchdog exited"
159
160 }
161
162
163 command_on_lxc() {
164 command=$1
165 shift
166
167 echo "# $command $1"
168
169 case "$command" in
170
171 start)
172         lxc_exists $1
173         cleanup_init_scripts $1
174         setup_inittab $1 ::power      "p0::powerfail:/sbin/init 0"
175         setup_inittab $1 ::ctrlaltdel "p6::ctrlaltdel:/sbin/init 6"
176         lxc_start $1
177         # give container 5 seconds to start more than one process
178         ( sleep 5 ; nohup $0 watchdog $1 >> /tmp/$1.log 2>/dev/null ) &
179         ;;
180 stop|halt)
181         lxc_exists $1
182         lxc_stop $1
183         ;;
184 reload|force-reload|restart|reboot)
185         lxc_kill $1 -SIGINT
186         ;;
187 watchdog)
188         lxc_watchdog $1
189         ;;
190 boot)
191         echo $1 > /var/lib/lxc/$1/on_boot
192         ;;
193 disable)
194         echo -n > /var/lib/lxc/$1/on_boot
195         ;;
196 *)
197         echo "Usage: $0 {start|stop|restart|status}" >&2
198         exit 3
199         ;;
200
201 esac
202
203 }
204
205 command=$1
206 shift
207
208 test "$command" = "status" && lxc_status && exit
209
210 if [ -z "$1" ] ; then
211         ls /var/lib/lxc/*/on_boot | while read path ; do
212                 name=`echo $path | cut -d/ -f5`
213                 if [ "$command" != "start" -o "$command" = "start" -a -s $path ] ; then
214                         command_on_lxc $command $name
215                 else
216                         echo "# skip $command $name"
217                 fi
218         done
219 else
220         while [ ! -z "$1" ] ; do
221                 command_on_lxc $command $1
222                 shift
223         done
224 fi
225