/[fai]/trunk/share/subroutines
ViewVC logotype

Contents of /trunk/share/subroutines

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1329 - (hide annotations) (download)
Thu Nov 28 12:54:42 2002 UTC (10 years, 5 months ago) by lange
File size: 18200 byte(s)
add link last to last action performed
new variable $LOGSERVER
1 lange 1300 # $Id$
2     #*********************************************************************
3     #
4     # subroutines -- useful subroutines for FAI
5     #
6     # This script is part of FAI (Fully Automatic Installation)
7     # (c) 2000-2002 by Thomas Lange, lange@informatik.uni-koeln.de
8     # Universitaet zu Koeln
9     #
10     #*********************************************************************
11     # This program is free software; you can redistribute it and/or modify
12     # it under the terms of the GNU General Public License as published by
13     # the Free Software Foundation; either version 2 of the License, or
14     # (at your option) any later version.
15     #
16     # This program is distributed in the hope that it will be useful, but
17     # WITHOUT ANY WARRANTY; without even the implied warranty of
18     # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19     # General Public License for more details.
20     #
21     # A copy of the GNU General Public License is available as
22     # `/usr/share/common-licences/GPL' in the Debian GNU/Linux distribution
23     # or on the World Wide Web at http://www.gnu.org/copyleft/gpl.html. You
24     # can also obtain it by writing to the Free Software Foundation, Inc.,
25     # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26     #*********************************************************************
27    
28     # source this file, then you have these function available in the shell
29    
30     # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
31     die() {
32    
33     # echo comment and exit installation
34     echo "$@"
35     exec bash
36     }
37     # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
38     defnop() {
39    
40     # define given list of subroutine names as dummy function;
41     # this will fake unknown commands
42    
43     local name
44     for name in "$@";do
45     eval "$name () { :;}"
46     done
47     }
48     # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
49     islinux() {
50    
51     # test is we are running on Linux
52     # [ X$OS_TYPE = X ] && OS_TYPE=`uname -s | tr '[A-Z]' '[a-z]'
53     if [ X$OS_TYPE = Xlinux ]; then
54     return 0
55     else
56     return 1
57     fi
58     }
59     # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
60     ifclass() {
61    
62     # test if a class is defined
63     local cl
64     for cl in $classes; do
65     [ x$cl = x$1 ] && return 0
66     done
67     return 1
68     }
69     # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
70     create_resolv_conf() {
71    
72 lange 1329 # can be an extern script
73 lange 1300 # create a resolv.conf using the DHCP or BOOTP information
74     if [ "$DNSSRVS" ]; then
75     [ "$DOMAIN" ] && echo "domain $DOMAIN" >/tmp/etc/resolv.conf
76     for dnshost in $DNSSRVS ; do
77     echo "nameserver $dnshost" >>/tmp/etc/resolv.conf
78     done
79     fi
80     }
81     # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
82     list_disks() {
83    
84 lange 1329 # can be an extern script
85 lange 1300 # print only every second entry; used by disk_info
86     local i ent list
87     list="$@"
88     i=0
89    
90     for ent in $list; do
91     if [ $i -eq 0 ]; then
92     echo $ent
93     i=1
94     else
95     i=0
96     fi
97     done
98     }
99     # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
100     mount_local_disks() {
101    
102     # try to mount all local disk partitions
103     local mountoption=ro
104     local disk partition partitions
105     fstabcount=0
106     [ "$1" = "rw" ] && mountoption=$1
107    
108     for disk in $disklist; do
109     partitions=`LC_ALL=C file -s /dev/$disk?* | \
110     egrep -v " empty$| data$| extended partition table" | \
111     perl -ne 'print "$1\n" if m#^/dev/(\S+):\s#'`
112     for partition in $partitions; do
113     mkdir -p $FAI_ROOT/$partition
114     mount -o $mountoption /dev/$partition $FAI_ROOT/$partition
115     # \ && echo $partition mounted successfully
116     if [ -f $FAI_ROOT/$partition/etc/$fstab ]; then
117     echo "/etc/$fstab found in $partition"
118     fstabpart=$partition # used in fstab_mount
119     fstablist="$fstablist $partition"
120     fstabcount=$((fstabcount+1))
121     fi
122     done
123     done
124     mount | grep $FAI_ROOT
125     }
126     # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
127     umount_local_disks() {
128    
129 lange 1329 # can be an extern script
130 lange 1300 local part
131     test -d $FAI_ROOT || return
132     for part in `grep $FAI_ROOT /proc/mounts | cut -d ' ' -f 2| sort -r`; do
133     umount $part
134     done
135     test -d $FAI_ROOT/ida && rmdir $FAI_ROOT/ida/*
136     test -d $FAI_ROOT/rd && rmdir $FAI_ROOT/rd/*
137     rmdir $FAI_ROOT/*
138     umount $FAI_ROOT
139     }
140     # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
141     rwmount() {
142    
143     # remount partition read/write
144     mount -o rw,remount $1
145     }
146     # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
147     fstab_mount() {
148    
149     if [ $fstabcount -eq 1 ]; then
150     # mount the root partition; then mount the rest according to fstab found
151     umount_local_disks
152     mount -o ro /dev/$fstabpart $FAI_ROOT
153     mount2dir $FAI_ROOT $FAI_ROOT/etc/$fstab
154     df
155     fi
156     [ $fstabcount -eq 0 ] && echo "No /etc/$fstab found"
157     [ $fstabcount -ge 2 ] && echo -n "Found multiple /etc/$fstab files in : $fstablist.\nUse mount2dir for mounting."
158     }
159     # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
160     save_log_local() {
161    
162 lange 1329
163     # can be an extern script
164 lange 1300 # save log files on local disk
165 lange 1329
166     # LOGSERVER is overridable until now
167     [ -z "$LOGSERVER" ] && LOGSERVER=$LOGSERVER
168 lange 1300 local logbase=$FAI_ROOT/var/log/fai
169     local thislog=$logbase/$HOSTNAME/$FAI_ACTION-$RUNDATE
170     find $LOGDIR -size 0 -type f | xargs -r rm
171     mkdir -p $thislog
172     cp -p $LOGDIR/* $thislog
173     ln -sf $HOSTNAME $logbase/localhost
174     ln -sf $FAI_ACTION-$RUNDATE $logbase/$HOSTNAME/last-$FAI_ACTION
175 lange 1329 ln -sf $FAI_ACTION-$RUNDATE $logbase/$HOSTNAME/last
176 lange 1300 }
177     # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
178     save_log_remote() {
179    
180 lange 1329 # can be an extern script
181     # save log files to $LOGUSER/$HOSTNAME/.. on $LOGSERVER
182 lange 1300 # also create a link last-$FAI_ACTION the the directory of the
183     # last action. The name of the log directory contains date and
184     # time of the action performed
185 lange 1329
186 lange 1300 [ "$LOGUSER" ] || return
187 lange 1329 # LOGSERVER is overridable until now
188     [ -z "$LOGSERVER" ] && LOGSERVER=$SERVER
189 lange 1300
190 lange 1329 echo "Saving log files remote to $LOGUSER@$LOGSERVER $HOSTNAME/$FAI_ACTION-$RUNDATE"
191 lange 1300 local thislog=$HOSTNAME/$FAI_ACTION-$RUNDATE
192     find $LOGDIR -size 0 -type f | xargs -r rm
193 lange 1329 $FAI_REMOTESH -l $LOGUSER $LOGSERVER " \
194     mkdir -p $thislog ;\
195     cd $HOSTNAME ;\
196     rm -f last-$FAI_ACTION ;\
197     ln -sf $FAI_ACTION-$RUNDATE last-$FAI_ACTION ;\
198     ln -sf $FAI_ACTION-$RUNDATE last"
199    
200     $FAI_REMOTECP -p $LOGDIR/* $LOGUSER@$LOGSERVER:$thislog
201 lange 1300 }
202     # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
203     save_dmesg() {
204    
205     dmesg > $LOGDIR/dmesg.log
206     }
207     # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
208     wait_for_jobs() {
209    
210 lange 1329 # can be an extern script
211 lange 1300 # wait for running (background) jobs to finish (e.g. update-auctex-elisp)
212     local i=0
213     while (jobsrunning); do
214     [ $(($i % 3)) -eq 0 ] && echo "Waiting for background jobs to finish."
215     i=$(($i+1))
216     sleep 10
217     done
218     }
219     # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
220     task() {
221    
222     # hooks are called before a task is called
223     # if a task is skipped, also its hooks are skipped
224     # a hook can set the flag, so the accociated task is skipped
225    
226     local taskname=$1
227    
228     [ -f $LOGDIR/skip.$taskname ] || call_hook $taskname
229    
230     if [ -f $LOGDIR/skip.$taskname ]; then
231     # skip task
232     rm $LOGDIR/skip.$taskname
233     [ "$verbose" ] && echo "Skiping task_$taskname"
234     else
235     echo "Calling task_$taskname"
236     task_$taskname
237     fi
238     }
239     # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
240     call_hook() {
241    
242     local hook=$1
243     local cl dflag hfile
244     [ "$debug" ] && dflag="-d"
245    
246     for cl in $classes; do
247     hfile=$FAI/hooks/${hook}.$cl
248     if [ -x $hfile ]; then
249     echo "Call hook: $hook.$cl"
250     # execute the hook
251     $hfile $dflag
252     # is that really good? Makes sense if hostname would
253     # be the first hook.
254     # execute only one hook if return value is 42
255     # [ $? -eq 42 ] && return
256     fi
257     if [ -x $hfile.source ]; then
258     echo "Source hook: $hook.$cl.source"
259     # source this hook
260     . $hfile.source $dflag
261     fi
262     done
263     }
264     # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
265     skiptask() {
266    
267     # mark all given tasks, so they will be skipped
268     local tasklist="$@"
269     local task
270    
271     for task in $tasklist; do
272     > $LOGDIR/skip.$task
273     done
274     }
275     # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
276     get_fai_dir() {
277    
278     # get /fai directory; mount it or get it from a cvs repository
279     if [ -z "$FAI_LOCATION" ]; then
280     [ "$debug" ] && echo "Warning $0: \$FAI_LOCATION not defined."
281     get_fai_cvs
282     else
283     mount $romountopt $FAI_LOCATION $FAI &&
284     echo "$FAI mounted from $FAI_LOCATION"
285     fi
286     # source user specific subroutines
287     [ -f $FAI/hooks/subroutines ] && . $FAI/hooks/subroutines
288     }
289     # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
290     get_fai_cvs() {
291    
292     # subroutine which gets $FAI (/fai) configuration directory from
293     # a cvs repository. You can redefine this subroutine if you need
294     # access via ftp, http, or from a database
295    
296     if [ "$FAI_CVSROOT" ] ; then
297     local TAG=""
298     echo "Checking out CVS"
299     [ -n "$FAI_CVSTAG" ] && TAG="-r $FAI_CVSTAG"
300     export FAI_CONFIG_AREA=$FAI
301     export FAI=/tmp/$(basename $FAI_CONFIG_AREA)
302    
303     [ "$debug" ] && echo "\$FAI now points to $FAI"
304    
305     if [ -d "$FAI_CONFIG_AREA" ] ; then
306     echo "Config found at $FAI_CONFIG_AREA: Copying"
307     cp -a $FAI_CONFIG_AREA $FAI
308     fi
309     cd /tmp
310     cvs -q -d"$FAI_CVSROOT" co -P -d $(basename "$FAI") \
311     $TAG $FAI_CVSMODULE > $LOGDIR/cvs.log
312     else
313     echo "Warning $0: Neither \$FAI_LOCATION nor \$FAI_CVSROOT are defined."
314     fi
315     }
316     # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
317     define_fai_flags() {
318    
319     # FAI_FLAGS are now comma separated, define all flags
320     FAI_FLAGS=`echo $FAI_FLAGS | sed -e 's/,/ /g'`
321     for flag in $FAI_FLAGS; do
322     # define this flag as 1
323     eval "$flag=1"
324     [ "$verbose" ] && echo "FAI_FLAGS: $flag=1"
325     done
326     }
327     # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
328     task_setup() {
329    
330     local flag
331     # set the system time and date using rdate or/and ntpdate
332     [ "$TIMESRVS_1" ] && rdate $TIMESRVS_1
333     [ "$NTPSRVS_1" ] && ntpdate -b -v $NTPSRVS
334    
335     define_fai_flags
336    
337     DNSDOMAIN=$DOMAIN # cfengine 1.5.3 can't use $DOMAIN
338     devnull=/dev/null
339     [ "$debug" ] && devnull=/dev/console
340    
341     # not yet used, maybe use a hook for that
342     # if [ "$FAI_EXTRA_MOUNT" ]; then
343     # mount $romountopt -n $FAI_EXTRA_MOUNT && echo "$FAI_EXTRA_MOUNT mounted"
344     # fi
345    
346     [ "$createvt" ] && {
347     # create two virtual terminals; acces via alt-F2 and alt-F3
348     echo "Press ctrl-c to interrupt FAI and to get a shell"
349     openvt -c2 /bin/bash ; openvt -c3 /bin/bash
350     trap 'echo "You can reboot with faireboot";bash' INT QUIT
351     }
352    
353     # start secure shell daemon for remote access
354     [ "$sshd" -a -x /usr/sbin/sshd ] && /usr/sbin/sshd
355     disk_info # get and define all information of local disks
356    
357     # when did FAI start, using localtime
358     RUNDATE=$(date +'%Y%m%d_%H%M%S')
359    
360     cat >> $rcsfaivar <<-EOM
361     RUNDATE=$RUNDATE
362     FAI_ACTION=$FAI_ACTION
363     LOGDIR=$LOGDIR
364     EOM
365     }
366     # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
367     task_action() {
368    
369     echo "FAI_ACTION: $FAI_ACTION"
370     case $FAI_ACTION in
371    
372     install)
373     echo Performing FAI installation. All data may be overwritten!
374     task install
375     ;;
376     sysinfo)
377     echo Showing system information.
378     task sysinfo
379     die Now you have a shell.
380     ;;
381     backup)
382     echo Doing backup of multiple partitions.
383     task backup
384     ;;
385     *)
386     if [ -f $FAI/hooks/$FAI_ACTION ]; then
387     echo "Calling user defined action: $FAI_ACTION"
388     $FAI/hooks/$FAI_ACTION
389     else
390     echo "ERROR: User defined action $FAI/hooks/$FAI_ACTION not found."
391     task_faiend
392     fi
393     ;;
394     esac
395     }
396     # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
397     task_defclass() {
398    
399     local newclasses addclasses class f
400    
401     cd $FAI/class || die "No directory $FAI/class found. No configuration in $FAI_LOCATION on the install server."
402     echo "Defining classes"
403    
404     [ -f $HOSTNAME ] && newclasses=`grep -v '^#' $HOSTNAME`
405     [ "$debug" ] && echo "newclasses= $newclasses"
406     classes="DEFAULT $newclasses"
407    
408     # alphabetical sort is important
409     for f in `ls S[0-9]*.{sh,pl,source}` ; do
410     if [ -x $f -a -f $f ]; then
411     newclasses=
412     [ "$verbose" ] && echo "Executing $f"
413     case $f in
414     *.pl) newclasses=`perl $f </dev/null | grep -v '^#'` ;;
415     *.sh) newclasses=`sh $f </dev/null | grep -v '^#'` ;;
416     *.source) . $f ;; # this script can define $newclasses!
417     esac
418     [ "$debug" ] && echo "newclasses= $newclasses"
419     classes="$classes $newclasses"
420     fi
421     done
422    
423     # scripts can also write additional classes to a file if they
424     # can't print them to stdout. Now read this file and define the classes
425     [ -f $LOGDIR/additional-classes ] && addclasses=`grep -v '^#' $LOGDIR/additional-classes`
426     [ "$debug" ] && echo "additonal classes: $addclasses"
427    
428     # now add the hostname (the only class in lowercase) and LAST to
429     # the list of classes
430     classes="$classes $addclasses $HOSTNAME LAST"
431    
432     # also define all classes in reverse order ($revclasses)
433     for class in $classes ; do
434     echo $class >> $LOGDIR/FAI_CLASSES
435     revclasses="$class $revclasses"
436     done
437    
438     # define classes as: a.b.c.d for cfengine -D
439     # this doesn't work without echo
440     cfclasses=`echo $classes`
441     cfclasses=${cfclasses// /.}
442     [ "$debug" ] && echo "cfclasses: $cfclasses"
443     }
444     # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
445     task_defvar() {
446    
447     local class
448     cd $FAI/class
449     for class in $classes ; do
450     if [ -f $class.var ]; then
451     [ "$verbose" ] && echo "Executing $class.var"
452     [ "$debug" ] && set -vx
453     . $class.var </dev/null
454     [ "$debug" ] && set +vx
455     fi
456     done
457    
458     # /fai/class/S* scripts or hooks can write variable definitions
459     # to additonal.var. now source these definitions
460     [ "$debug" ] && set -vx
461     [ -f $LOGDIR/additional.var ] && . $LOGDIR/additional.var
462     [ "$debug" ] && set +vx
463     }
464     # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
465     task_mountdisks() {
466    
467     [ ! -f $LOGDIR/$fstab ] && die "No $LOGDIR/$fstab created."
468     if islinux; then
469     # mount swap space
470     local sd vflag
471     [ "$verbose" ] && vflag=-v
472     for sd in $SWAPLIST; do
473     swapon $vflag $sd
474     done
475     fi
476     mount2dir $FAI_ROOT $LOGDIR/$fstab
477     }
478     # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
479     task_configure() {
480    
481     # execute all scripts that match the name of a class.
482     # If class is a directory, execute all $class/S[0-9]* scripts in
483     # it, but do not execute files ending in ~
484    
485     local class f
486    
487     cd $FAI/scripts
488     for class in $classes ; do
489     [ -x $class -a -f $class ] && do_script $class
490     if [ -d $class ]; then
491     for f in `ls $class/S[0-9]*[^~]` ; do
492     [ -x $f -a -f $f ] && do_script $f
493     done
494     fi
495     done
496     }
497     # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
498     do_script() {
499    
500     # execute scripts and save their outpu in log files
501     # cfengine, shell, perl and expect scripts are known types
502     local shelldebug file filetype
503    
504     file=$1
505    
506     cd $FAI/scripts
507     filetype=`file $file`
508     shelldebug=
509     case $filetype in
510     *"Bourne shell script"*)
511     [ "$debug" ] && shelldebug="sh -x" ;;
512     *"Bourne-Again shell script"*)
513     [ "$debug" ] && shelldebug="bash -x" ;;
514     esac
515    
516     case $filetype in
517    
518     *"executable shell script"*|*"/bash script"*|*"Bourne shell script"*|*"Bourne-Again shell script"*)
519     echo "Executing $shelldebug shell: $file"
520     echo "===== shell: $file =====" >> $LOGDIR/shell.log 2>&1
521     $shelldebug ./$file >> $LOGDIR/shell.log 2>&1
522     ;;
523    
524     *"cfengine script"*)
525     echo "Executing cfengine: $file"
526     echo "===== cfengine: $file =====" >> $LOGDIR/cfengine.log 2>&1
527     ./$file --no-lock -v -f $file -D${cfclasses} >> $LOGDIR/cfengine.log 2>&1
528     ;;
529    
530     *"perl script"*)
531     echo "Executing perl: $file"
532     echo "===== perl: $file =====" >> $LOGDIR/perl.log 2>&1
533     ./$file >> $LOGDIR/perl.log 2>&1
534     ;;
535    
536     *"expect script"*)
537     echo "Executing expect: $file"
538     echo "===== expect: $file =====" >> $LOGDIR/expect.log 2>&1
539     ./$file >> $LOGDIR/expect.log 2>&1
540     ;;
541    
542     *) echo "File $file has unsupported type $filetype." ;;
543     esac
544     }
545     # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
546     task_savelog() {
547    
548     save_log_local
549     save_log_remote
550     }
551     # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
552     task_faiend() {
553    
554     wait_for_jobs
555     echo "Press <RETURN> to reboot or ctrl-c to execute a shell"
556     # reboot without prompting if FAI_FLAG reboot is set
557     [ -z $reboot ] && read
558     echo "Rebooting $HOSTNAME now"
559     cd /
560     sync
561     umount -ar
562     exec reboot -dfi
563     }
564     # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
565     task_backup() {
566    
567     # NOT YET USED. IT'S ONLY AN IDEA
568    
569     # FAI_BACKUP_LIST contains backup options
570     # proposed format: "hda1 hda3 hda12 sda2 '0 0 1 1'"
571     # list of devices list of backup levels
572     # this subroutine is not yet tested, not yet used
573     # It's only an idea how a backup could be made
574     die "Task backup not yet used. But you can use the hook backup."
575     local partition
576     mount_local_disks
577     for partition in $SAVE_DEVICES ; do
578     # tar cf - $FAI_ROOT/$partition | $FAI_REMOTESH -l $LOGUSER $SERVER dd if= of=$HOSTNAME.$partition.tar
579     dump 0f $LOGUSER@$SERVER:backup/$HOSTNAME/$partition.dmp $FAI_ROOT/$partition
580     done
581     }
582     # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
583     task_install() {
584    
585     > $stamp
586    
587     save_dmesg
588     load_keymap_consolechars
589    
590     task partition
591     task mountdisks
592     task extrbase
593     task mirror
594     task updatebase
595     task instsoft
596     task configure
597     task finish
598     date
599     echo -e "FAI finished.\a"
600     task chboot
601    
602     rm -f $stamp
603     # save again, because new messages could be created
604     save_dmesg
605     task savelog
606    
607     if [ -f $stamp ]; then
608     echo "Error while executing commands in subshell."
609     echo "$stamp was not removed."
610     die "Please look at the log files in $LOGDIR for errors."
611     fi
612     task faiend
613     }
614     # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

  ViewVC Help
Powered by ViewVC 1.1.5