Configuration generalised so that all options can be set via
[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 >&2 <<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 >&2 <<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 # create base image
205 create_base() {
206
207     NAME="$BASENAME"
208     DISK="$VIRTBASE/$NAME.img"
209
210     mkdir -p $KVMLOG
211
212     echo "Creating the disk"
213     qemu-img create -f $BASE_FORMAT "$DISK" $DISKSIZE
214
215     rm -rf tmp
216     mkdir -p mnt tmp tmp/ISO
217
218     setup_timezone
219     setup_repos
220
221     echo "Creating kickstart file from template"
222     substitute_vars "$KICKSTART" "tmp/ks.cfg"
223
224     if [ $INSTALLKEY = "--skip" ]; then
225         cat <<EOF
226 --------------------------------------------------------------------------------------
227 WARNING: You have not entered an install key. Some RHEL packages will not be installed.
228
229 Please enter a valid RHEL install key in your config file like this:
230
231   INSTALLKEY="1234-5678-0123-4567"
232
233 The install will continue without an install key in 5 seconds
234 --------------------------------------------------------------------------------------
235 EOF
236         sleep 5
237     fi
238     
239     echo "Creating kickstart floppy"
240     dd if=/dev/zero of=tmp/floppy.img bs=1024 count=1440
241     mkdosfs tmp/floppy.img
242     mount -o loop -t msdos tmp/floppy.img mnt
243     cp tmp/ks.cfg mnt
244     mount -o loop,ro $ISO tmp/ISO
245     
246     echo "Setting up bootloader"
247     cp tmp/ISO/isolinux/isolinux.bin tmp
248     cp tmp/ISO/isolinux/vmlinuz tmp
249     cp tmp/ISO/isolinux/initrd.img tmp
250     umount tmp/ISO
251     umount mnt
252
253     UUID=`uuidgen`
254
255     substitute_vars $INSTALL_TEMPLATE tmp/$NAME.xml
256
257     rm -f $KVMLOG/serial.$NAME
258
259     # boot the install CD
260     $VIRSH create tmp/$NAME.xml
261
262     echo "Waiting for install to start"
263     sleep 2
264     
265     # wait for the install to finish
266     if ! waitfor $KVMLOG/serial.$NAME "you may safely reboot your system" 3600; then
267         $VIRSH destroy $NAME
268         echo "Failed to create base image $DISK"
269         exit 1
270     fi
271     
272     $VIRSH destroy $NAME
273
274     ls -l $DISK
275     cat <<EOF
276
277 Install finished, base image $DISK created
278
279 You may wish to run
280    chattr +i $DISK
281 To ensure that this image does not change
282
283 Note that the root password has been set to $ROOTPASSWORD
284
285 EOF
286 }
287
288
289
290 ###############################
291 # boot the base disk
292 boot_base() {
293     CLUSTER="$1"
294
295     NAME="$BASENAME"
296     DISK="$VIRTBASE/$NAME.img"
297
298     rm -rf tmp
299     mkdir -p tmp
300
301     IPNUM=$FIRSTIP
302     CLUSTER="base"
303
304     mount_disk $DISK
305     setup_base
306     unmount_disk
307
308     UUID=`uuidgen`
309     
310     echo "Creating $NAME.xml"
311     substitute_vars $BOOT_TEMPLATE tmp/$NAME.xml
312     
313     # boot the base system
314     $VIRSH create tmp/$NAME.xml
315 }
316
317 ###############################
318 # test the proxy setup
319 test_proxy() {
320     export http_proxy=$WEBPROXY
321     wget -O /dev/null $INSTALL_SERVER
322     echo "Proxy OK"
323 }
324
325 ######################################################################
326
327 . "$installdir/functions"
328 . "$installdir/config.default"
329
330 ############################
331 # parse command line options
332 long_opts=$(getopt_config_options)
333 getopt_output=$(getopt -n autocluster -o "c:xh" -l help,dump -l "$long_opts" -- "$@")
334 [ $? != 0 ] && usage
335
336 use_default_config=true
337
338 # We 2 passes of the options.  The first time we just handle usageor the first pass
339 eval set -- "$getopt_output"
340 while true ; do
341     case "$1" in
342         -c) shift 2 ; use_default_config=false ;;
343         --) shift ; break ;;
344         --dump|-x) shift ;;
345         -h|--help) usage ;; # Usage should be shown here for real defaults.
346         --*) shift 2 ;; # Assume other long opts are valid and take an arg.
347         *) usage ;; # shouldn't happen, so this is reasonable.
348     esac
349 done
350
351 config="./config"
352 $use_default_config && [ -r "$config" ] && . "$config"
353
354 eval set -- "$getopt_output"
355
356 while true ; do
357     case "$1" in
358         -c) . "`dirname $2`/$2" ; shift 2 ; conf_done=true ;;
359         -x) set -x; shift ;;
360         --dump) dump_config ;;
361         --) shift ; break ;;
362         -h|--help) usage ;; # Redundant.
363         --*)
364             # Putting --opt1|opt2|... into a variable and having case
365             # match against it as a pattern doesn't work.  The | is
366             # part of shell syntax, so we need to do this.  Look away
367             # now to stop your eyes from bleeding! :-)
368             x=",${long_opts}" # Now each option is surrounded by , and :
369             if [ "$x" != "${x#*,${1#--}:}" ] ; then
370                 # Our option, $1, surrounded by , and : was in $x, so is legal.
371                 setconf_longopt "$1" "$2"; shift 2
372             else
373                 usage
374             fi
375             ;;
376         *) usage ;; # shouldn't happen, so this is reasonable.
377     esac
378 done
379
380 # catch errors
381 set -e
382 set -E
383 trap 'es=$?; 
384       echo ERROR: failed in function \"${FUNCNAME}\" at line ${LINENO} of ${BASH_SOURCE[0]} with code $es; 
385       exit $es' ERR
386
387 LOWDOMAIN=`echo $DOMAIN | tr A-Z a-z`
388
389 # check for needed programs 
390 check_command nbd-client
391 check_command expect
392 check_command qemu-nbd
393
394 [ $# -lt 1 ] && usage
395
396 command="$1"
397 shift
398
399 case $command in
400     create)
401         type=$1
402         shift
403         case $type in
404             base)
405                 [ $# != 0 ] && usage
406                 create_base;
407                 ;;
408             cluster)
409                 [ $# != 1 ] && usage
410                 create_cluster "$1";
411                 ;;
412             node)
413                 [ $# != 2 ] && usage
414                 create_node "$1" "$2";
415                 ;;
416             tsm)
417                 [ $# != 1 ] && usage
418                 create_tsm "$1";
419                 ;;
420             *)
421                 usage;
422                 ;;
423         esac
424         ;;
425     mount)
426         [ $# != 1 ] && usage
427         mount_disk "$1"
428         ;;
429     unmount)
430         [ $# != 0 ] && usage
431         unmount_disk
432         ;;
433     bootbase)
434         boot_base;
435         ;;
436     testproxy)
437         test_proxy;
438         ;;
439     *)
440         usage;
441         ;;
442 esac
443
444