Usage message now goes to stdout to enable easier use with grep. New
[tridge/autocluster.git] / autocluster
1 #!/bin/bash
2 # main autocluster script
3 #
4 # Copyright (C) Andrew Tridgell  2008
5 # Copyright (C) Martin Schwenke  2008
6 #
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
11 #   
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
16 #   
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, see <http://www.gnu.org/licenses/>.
19
20 if [ -f "$0" ]; then
21     installdir="`dirname \"$0\"`"
22 else
23     autocluster=`which $0`
24     installdir="`dirname \"$autocluster\"`"
25 fi
26
27 ####################
28 # show program usage
29 usage ()
30 {
31     cat <<EOF
32 Usage: autocluster [OPTION] ... <COMMAND>
33   options:
34     -c <file>    specify config file (default is "config")
35     -x           enable script debugging
36     --dump       dump config settings and exit
37
38   configuration options:
39 EOF
40
41     usage_config_options
42
43     cat <<EOF
44
45   commands:
46      create base
47            create a base image
48
49      create cluster CLUSTERNAME
50            create a full cluster
51
52      create node CLUSTERNAME NODENUMBER
53            create one cluster node
54
55      create tsm CLUSTERNAME
56            create a TSM server node
57
58      mount DISK
59            mount a qemu disk on mnt/
60
61      unmount
62            unmount a qemu disk from mnt/
63
64      bootbase
65            boot the base image
66
67      testproxy
68            test your proxy setup
69 EOF
70     exit 1
71 }
72
73
74 ###############################
75 # create a single node
76 create_node() {
77     CLUSTER="$1"
78     NODENUMBER="$2"
79     NAME="$CLUSTER""n$NODENUMBER"
80     BASE="$VIRTBASE/$BASENAME.img"
81     DISK="$VIRTBASE/$CLUSTER/$NAME.qcow2"
82     NUMSHARED=3
83
84     # first node might need more memory for SoFS GUI
85     if [ $NODENUMBER = 1 -a $GUIMEM -gt $MEM ]; then
86         NODEMEM=$GUIMEM
87     else
88         NODEMEM=$MEM
89     fi
90     echo "Creating cluster node $NAME"
91
92     mkdir -p $VIRTBASE/$CLUSTER
93
94     echo "Creating the disk"
95     rm -f "$DISK"
96     qemu-img create -b "$BASE" -f qcow2 "$DISK"
97
98     IPNUM=`expr $FIRSTIP + $NODENUMBER`
99
100     mount_disk $DISK
101     setup_base
102     setup_network
103     unmount_disk
104
105     mkdir -p tmp
106
107     MAC1=`get_macaddr $CLUSTER $NODENUMBER 1`
108     MAC2=`get_macaddr $CLUSTER $NODENUMBER 2`
109     MAC3=`get_macaddr $CLUSTER $NODENUMBER 3`
110     UUID=`uuidgen`
111     
112     echo "Creating $NAME.xml"
113     substitute_vars $NODE_TEMPLATE tmp/$NAME.xml
114     
115     # install the XML file
116     $VIRSH undefine $NAME > /dev/null 2>&1 || true
117     $VIRSH define tmp/$NAME.xml
118 }
119
120
121 ###############################
122 # create a TSM node
123 create_tsm() {
124     CLUSTER="$1"
125     NAME="$CLUSTER""tsm"
126     BASE="$VIRTBASE/$BASENAME.img"
127     DISK="$VIRTBASE/$CLUSTER/$NAME.qcow2"
128     TSMDISK="$VIRTBASE/$CLUSTER/tsmstorage.qcow2"
129     
130     echo "Creating TSM cluster node $NAME"
131     
132     mkdir -p $VIRTBASE/$CLUSTER tmp
133     
134     echo "Creating the disk"
135     rm -f "$DISK"
136     qemu-img create -b "$BASE" -f qcow2 "$DISK"
137     
138     echo "Creating tsm disk"
139     qemu-img create -f qcow2 "$TSMDISK" $TSMDISKSIZE
140     
141     # TSM server is first IP in the cluster
142     IPNUM=$FIRSTIP
143
144     mount_disk $DISK
145     setup_base
146     setup_network
147     unmount_disk
148     
149     UUID=`uuidgen`
150     MAC1=`get_macaddr $CLUSTER 0 0`
151     
152     echo "Creating $NAME.xml"
153     substitute_vars $TSM_TEMPLATE tmp/$NAME.xml
154     
155     # install the XML file
156     $VIRSH undefine $NAME > /dev/null 2>&1 || true
157     $VIRSH define tmp/$NAME.xml
158 }
159
160
161 ###############################
162 # create a whole cluster
163 create_cluster() {
164     CLUSTER="$1"
165
166     mkdir -p $VIRTBASE/$CLUSTER tmp
167     mkdir -p $KVMLOG
168
169     echo "Creating 3 shared disks"
170     for i in `seq 1 3`; do
171         # setup a nice ID at the start of the disk
172         qemu-img create -f raw $VIRTBASE/$CLUSTER/shared$i $SHAREDDISKSIZE
173         echo "SOFS-`uuidgen`" > tmp/diskid
174         dd if=tmp/diskid of=$VIRTBASE/$CLUSTER/shared$i conv=notrunc bs=1 > /dev/null 2>&1
175     done
176
177     echo "Creating $NUMNODES base nodes"
178     for i in `seq 1 $NUMNODES`; do
179         create_node "$CLUSTER" $i
180     done
181
182     if [ $WITH_TSM_NODE -eq 1 ]; then
183       echo "Creating TSM server node"
184       create_tsm "$CLUSTER"
185     fi
186
187     echo "# autocluster $CLUSTER" > hosts.$CLUSTER
188     [ $WITH_TSM_NODE -eq 1 ] && {
189         echo "$IPBASE.0.$FIRSTIP ${CLUSTER}tsm.$LOWDOMAIN ${CLUSTER}tsm" >> hosts.$CLUSTER
190     }
191     for i in `seq 1 $NUMNODES`; do
192         echo "$IPBASE.0.`expr $FIRSTIP + $i` ${CLUSTER}n$i.$LOWDOMAIN ${CLUSTER}n$i" >> hosts.$CLUSTER
193     done
194     echo >> hosts.$CLUSTER
195
196     echo "Cluster $CLUSTER created"
197     echo "You may want to add this to your /etc/hosts file:"
198     cat hosts.$CLUSTER
199
200     echo
201 }
202
203 ###############################
204 # test the proxy setup
205 test_proxy() {
206     export http_proxy=$WEBPROXY
207     wget -O /dev/null $INSTALL_SERVER || {
208         echo "Your WEBPROXY setting \"$WEBPROXY\" is not working"
209         exit 1
210     }
211     echo "Proxy OK"
212 }
213
214
215 ###################
216 # create base image
217 create_base() {
218
219     NAME="$BASENAME"
220     DISK="$VIRTBASE/$NAME.img"
221
222     mkdir -p $KVMLOG
223
224     echo "Testing WEBPROXY $WEBPROXY"
225     test_proxy
226
227     echo "Creating the disk"
228     qemu-img create -f $BASE_FORMAT "$DISK" $DISKSIZE
229
230     rm -rf tmp
231     mkdir -p mnt tmp tmp/ISO
232
233     setup_timezone
234     setup_repos
235
236     echo "Creating kickstart file from template"
237     substitute_vars "$KICKSTART" "tmp/ks.cfg"
238
239     if [ $INSTALLKEY = "--skip" ]; then
240         cat <<EOF
241 --------------------------------------------------------------------------------------
242 WARNING: You have not entered an install key. Some RHEL packages will not be installed.
243
244 Please enter a valid RHEL install key in your config file like this:
245
246   INSTALLKEY="1234-5678-0123-4567"
247
248 The install will continue without an install key in 5 seconds
249 --------------------------------------------------------------------------------------
250 EOF
251         sleep 5
252     fi
253     
254     echo "Creating kickstart floppy"
255     dd if=/dev/zero of=tmp/floppy.img bs=1024 count=1440
256     mkdosfs tmp/floppy.img
257     mount -o loop -t msdos tmp/floppy.img mnt
258     cp tmp/ks.cfg mnt
259     mount -o loop,ro $ISO tmp/ISO
260     
261     echo "Setting up bootloader"
262     cp tmp/ISO/isolinux/isolinux.bin tmp
263     cp tmp/ISO/isolinux/vmlinuz tmp
264     cp tmp/ISO/isolinux/initrd.img tmp
265     umount tmp/ISO
266     umount mnt
267
268     UUID=`uuidgen`
269
270     substitute_vars $INSTALL_TEMPLATE tmp/$NAME.xml
271
272     rm -f $KVMLOG/serial.$NAME
273
274     # boot the install CD
275     $VIRSH create tmp/$NAME.xml
276
277     echo "Waiting for install to start"
278     sleep 2
279     
280     # wait for the install to finish
281     if ! waitfor $KVMLOG/serial.$NAME "you may safely reboot your system" 3600; then
282         $VIRSH destroy $NAME
283         echo "Failed to create base image $DISK"
284         exit 1
285     fi
286     
287     $VIRSH destroy $NAME
288
289     ls -l $DISK
290     cat <<EOF
291
292 Install finished, base image $DISK created
293
294 You may wish to run
295    chattr +i $DISK
296 To ensure that this image does not change
297
298 Note that the root password has been set to $ROOTPASSWORD
299
300 EOF
301 }
302
303
304
305 ###############################
306 # boot the base disk
307 boot_base() {
308     CLUSTER="$1"
309
310     NAME="$BASENAME"
311     DISK="$VIRTBASE/$NAME.img"
312
313     rm -rf tmp
314     mkdir -p tmp
315
316     IPNUM=$FIRSTIP
317     CLUSTER="base"
318
319     mount_disk $DISK
320     setup_base
321     unmount_disk
322
323     UUID=`uuidgen`
324     
325     echo "Creating $NAME.xml"
326     substitute_vars $BOOT_TEMPLATE tmp/$NAME.xml
327     
328     # boot the base system
329     $VIRSH create tmp/$NAME.xml
330 }
331
332 ######################################################################
333
334 . "$installdir/functions"
335 . "$installdir/config.default"
336
337 ############################
338 # parse command line options
339 long_opts=$(getopt_config_options)
340 getopt_output=$(getopt -n autocluster -o "c:xh" -l help,dump -l "$long_opts" -- "$@")
341 [ $? != 0 ] && usage
342
343 use_default_config=true
344
345 # We 2 passes of the options.  The first time we just handle usage and
346 # check whether -c is being used.
347 eval set -- "$getopt_output"
348 while true ; do
349     case "$1" in
350         -c) shift 2 ; use_default_config=false ;;
351         --) shift ; break ;;
352         --dump|-x) shift ;;
353         -h|--help) usage ;; # Usage should be shown here for real defaults.
354         --*) shift 2 ;; # Assume other long opts are valid and take an arg.
355         *) usage ;; # shouldn't happen, so this is reasonable.
356     esac
357 done
358
359 config="./config"
360 $use_default_config && [ -r "$config" ] && . "$config"
361
362 eval set -- "$getopt_output"
363
364 while true ; do
365     case "$1" in
366         -c) . "`dirname $2`/$2" ; shift 2 ; conf_done=true ;;
367         -x) set -x; shift ;;
368         --dump) dump_config ;;
369         --) shift ; break ;;
370         -h|--help) usage ;; # Redundant.
371         --*)
372             # Putting --opt1|opt2|... into a variable and having case
373             # match against it as a pattern doesn't work.  The | is
374             # part of shell syntax, so we need to do this.  Look away
375             # now to stop your eyes from bleeding! :-)
376             x=",${long_opts}" # Now each option is surrounded by , and :
377             if [ "$x" != "${x#*,${1#--}:}" ] ; then
378                 # Our option, $1, surrounded by , and : was in $x, so is legal.
379                 setconf_longopt "$1" "$2"; shift 2
380             else
381                 usage
382             fi
383             ;;
384         *) usage ;; # shouldn't happen, so this is reasonable.
385     esac
386 done
387
388 # catch errors
389 set -e
390 set -E
391 trap 'es=$?; 
392       echo ERROR: failed in function \"${FUNCNAME}\" at line ${LINENO} of ${BASH_SOURCE[0]} with code $es; 
393       exit $es' ERR
394
395 LOWDOMAIN=`echo $DOMAIN | tr A-Z a-z`
396
397 # check for needed programs 
398 check_command nbd-client
399 check_command expect
400 check_command $QEMU_NBD
401
402 [ $# -lt 1 ] && usage
403
404 command="$1"
405 shift
406
407 case $command in
408     create)
409         type=$1
410         shift
411         case $type in
412             base)
413                 [ $# != 0 ] && usage
414                 create_base;
415                 ;;
416             cluster)
417                 [ $# != 1 ] && usage
418                 create_cluster "$1";
419                 ;;
420             node)
421                 [ $# != 2 ] && usage
422                 create_node "$1" "$2";
423                 ;;
424             tsm)
425                 [ $# != 1 ] && usage
426                 create_tsm "$1";
427                 ;;
428             *)
429                 usage;
430                 ;;
431         esac
432         ;;
433     mount)
434         [ $# != 1 ] && usage
435         mount_disk "$1"
436         ;;
437     unmount)
438         [ $# != 0 ] && usage
439         unmount_disk
440         ;;
441     bootbase)
442         boot_base;
443         ;;
444     testproxy)
445         test_proxy;
446         ;;
447     *)
448         usage;
449         ;;
450 esac
451
452