Next Previous Contents

9. adcn script

#!/bin/bash
#-----------------------------------------------------------------------------
# 
# /usr/local/sbin/adcn
# ftp://ftp.sci.usq.edu.au/pub/jacek/beowulf-utils
#
# Add Disk-less Client Node
#
# Version   : 0.0.5
#
# Date      : 5 September 1998
#
# Author    : Jacek Radajewski 
#             jacek@usq.edu.au
#
# Purpose   : This script adds a new node to a disk-less-client Beowulf cluster.
#             adcn assumes Red Hat 5.0 or 5.1  and might not work on other versions
#             of Red Hat or other distributions of Linux .  adcn uses the /tftpboot/Template
#             directory to create NFS root file system for the client node.  
#             /tftpboot/Template should be created with the setup_template script, 
#             which can be found at ftp://ftp.sci.usq.edu.au/pub/jacek/beowulf-utils
#
# Command line options :
#
#        -f
#              Force installation even if unknown Linux release.  adcn normally checks for
#              for version of Red Hat Linux, and if the version number is not 5.0 or 5.1 
#              then adcn will give up.  adcn will also give up if the Linux distribution
#              is not Red Hat.  This option ignores release and version checking.
#              
#        -i ip address
#              IP address of the new disk-less client node.
#        
#        -m hardware address
#              MAC (hardware) address of the new disk-less client node.  -m is ignored when
#              used together with the -l option.
# 
#        -l interface
#              listen to RARP requests on interface and use the 'sniffed' address
#              as the hardware address of the new disk-less client node.
#              This overides -m option
#
#        -c client name 
#              hostname of the new disk-less client node.
#              You must specify first name only, not the FQDN.
#              For example node1 and NOT node1.beowulf.my.domain
#
#        -d domain name
#              This is optional and if not specified
#              the DNS domain of the server will be used.
#
#        -n netmask address of the new node.  Default value is used if this is not specified
#
#        -g gateway address.  Server's IP is used as the default value if gateway is not
#              specified.  Using
#
#        -N network address
#
#        -b broadcast address
#
#        -s list supported distributions and version of Linux
#
#        -h help
#
#-----------------------------------------------------------------------------

show_help () {

    echo -e "adcn options\n"
    echo "[-f]             : force installation even if adcn does not support this"
    echo "                   distribution of Linux or version of Red Hat Linux"
    echo " -i ip_address   : IP Addrees of the disk-less client node"
    echo "[-m mac_address] : MAC or hardware address of the disk-less client node"
    echo " -l interface    : Listen for RARP request on the interface and use the sniffed"
    echo "                   hardware address as the hardware address of client node"
    echo "                   If -m is specified with this option, given MAC address is"
    echo "                   ignored. (not implemented)"
    echo " -c client_name  : Host name of the disk-less client node.  This must the first"
    echo "                   name of the node and not the fully qualified domain name"
    echo "[-d domain_name] : Domain name.  If not specified servers domain will be used."
    echo "[-n netmask]     : Netmask address.  If not specified the default netmask"
    echo "                   255.255.255.0 will be used.  For clusters with more than 255"
    echo "                   nodes this should be changed to 255.255.0.0"
    echo "[-g gateway]     : Default gateway for the disk-less client node.  If not" 
    echo "                   specified, server node is used as the default gateway"
    echo "[-N net_address] : Network address"
    echo "[-b broadcast]   : Broadcast address"
    echo "[-h]             : This help message"
    echo "[-s]             : List supported distributions and versions of Linux"
    exit 0
}

# set few default values before processing command line arguments

export FORCE=false
export LISTEN=false
export SERVER=$(/bin/hostname)
export DOMAIN=$(/bin/dnsdomainname)
export HOST=none
export IPADDR=none
export MACADDR=none
export NETMASK=255.255.255.0
export BROADCAST=10.0.0.255
export NETWORK=10.0.0.0
export GATEWAY=10.0.0.1

# process command line options

while getopts ":fhd:i:m:c:n:g:N:b:l:" opt; do
    case $opt in
        f ) export FORCE=true;;
        d ) export DOMAIN=$OPTARG;;
        i ) export IPADDR=$OPTARG;;
        m ) export MACADDR=$OPTARG;;
        c ) export HOST=$OPTARG;;
        n ) export NETMASK=$OPTARG;;
        g ) export GATEWAY=$OPTARG;;
        N ) export NETWORK=$OPTARG;;
        b ) export BROADCAST=$OPTARG;;
        l ) export L_INTERFACE=$OPTARG
            export LISTEN=true;;
        h ) show_help;;
        \? ) echo 'adcn -h for help'
             exit 1
    esac
done

# check if everything is set

if [ $HOST = 'none' ] || [ $IPADDR = 'none' ] || [ $MACADDR = 'none' ] ; then
    echo 'adcn -h for help'
    exit 1
fi

# make sure that the host name is not a FQDN

echo $HOST | grep "\." > /dev/null 2>&1
if [ $? = 0 ] ; then
    echo "Host name cannot be a fully qualified domain name.  Use -d to set domain."
    exit 1
fi


# simple and incomplete check of the MAC address

if [ $(echo $MACADDR | cut -f 6 -d ":")test = "test" ] ; then
    echo "$MACADDR is not a valid MAC address"
    exit 1
fi

echo "Adding $HOST.$DOMAIN - IP- $IPADDR - MAC- $MACADDR to the cluster ... "

# check linux release but not if forced install
# at this stage only check for Red Hat 5.0

if [ $FORCE = 'false' ] ; then
    if [ -f /etc/redhat-release ] ; then
    
        cat /etc/redhat-release | grep "Hurricane" > /dev/null 2>&1
        if [ $? = 0 ] ; then
            export REDHAT=Hurricane
        else 
            echo "This script might not work with Red Hat Linux $(cat /etc/redhat-release)"
            echo "Use -f to force installation"
            exit 1
        fi
    else 
        echo "Can't find /etc/redhat-release file."
        echo "Not a Red Hat Linux distribution.  Giving up"
        echo "Use -f to force installation.  Good luck."
        exit 1
    fi
fi



# the location of our template
# you must create template before you run this script !!!
# use the setup_template script to create the template
# and then customize it for your needs
export TEMPLATE_DIR=/tftpboot/Template

export DEST_DIR=/tftpboot/$IPADDR

#umask 022


#-----------------------------------------------------------------------------
# check if this IP address already exists

if [ -f $DEST_DIR ] ; then
    echo "$DEST_DIR entry exists.  Giving up."
    exit 1
fi

# do few other checks before going ahead

if [ ! -d $TEMPLATE_DIR ] ; then
    echo "Cannot find Template directory $TEMPLATE_DIR.  Giving up."
    exit 1
fi

#--------------------------------------------------------------------
# create the root directory for new node

/bin/mkdir /tftpboot/$IPADDR

# we also want the name of the new node to be a link to the real (IP address)
# directory

/bin/ln -sf /tftpboot/$IPADDR /tftpboot/$HOST
/bin/ln -sf /tftpboot/$IPADDR /tftpboot/$HOST.$DOMAIN

# create sub directories

/bin/mkdir $DEST_DIR/bin
/bin/mkdir $DEST_DIR/boot
/bin/mkdir $DEST_DIR/dev
/bin/mkdir $DEST_DIR/etc
/bin/mkdir $DEST_DIR/home
/bin/mkdir $DEST_DIR/lib
/bin/mkdir $DEST_DIR/mnt
/bin/mkdir $DEST_DIR/proc
/bin/mkdir $DEST_DIR/root
/bin/mkdir $DEST_DIR/sbin
/bin/mkdir $DEST_DIR/tmp
/bin/mkdir $DEST_DIR/usr
/bin/mkdir $DEST_DIR/var

/bin/chmod 777 $DEST_DIR/tmp

echo "Building NFS root file system ..."

#-----------------------------------------------------------------------------
# we now create the files in all of the directories
# we make hard links to files in our Template directory
#-----------------------------------------------------------------------------

#-----------------------------------------------------------------------------
# /bin
echo -n " /bin "
cd $TEMPLATE_DIR/bin
for directory in $(/usr/bin/find . -not -name '.' -type d) ; do
    /bin/mkdir $DEST_DIR/bin/$directory
done
for file in $(/usr/bin/find . -type f -maxdepth 1 -follow) ; do
    /bin/ln $TEMPLATE_DIR/bin/$file $DEST_DIR/bin/$file
done

#-----------------------------------------------------------------------------
# /boot
echo -n " /boot "
cd $TEMPLATE_DIR/boot
for directory in $(/usr/bin/find . -not -name '.' -type d) ; do
    /bin/mkdir $DEST_DIR/boot/$directory
done
for file in $(/usr/bin/find . -type f -maxdepth 1) ; do
    /bin/ln $TEMPLATE_DIR/boot/$file $DEST_DIR/boot/$file
done

#-----------------------------------------------------------------------------
#                                   /dev
#-----------------------------------------------------------------------------

echo -n " /dev "
cd $TEMPLATE_DIR/dev

# Linking of devices is still very shaky.  There are problems
# with linking /dev/fd, /dev/stdin, /dev/stderr, and /dev/stdout
# directories.  These are done manually.

/bin/ln -sf ../proc/self/fd          $DEST_DIR/dev/fd
/bin/ln -f  $TEMPLATE_DIR/dev/stdin  $DEST_DIR/dev/stdin
/bin/ln -f  $TEMPLATE_DIR/dev/stdout $DEST_DIR/dev/stdout
/bin/ln -f  $TEMPLATE_DIR/dev/stderr $DEST_DIR/dev/stderr

for directory in $(/usr/bin/find . -not -name '.' -type d) ; do
    /bin/mkdir $DEST_DIR/dev/$directory
done
# link files  block, character, then normal files (e.g. MAKEDEV)
for file in $(/usr/bin/find . -type c -follow -mount) ; do
    /bin/ln -fd $TEMPLATE_DIR/dev/$file $DEST_DIR/dev/$file
done
for file in $(/usr/bin/find . -type b -follow -mount) ; do
    /bin/ln -fd $TEMPLATE_DIR/dev/$file $DEST_DIR/dev/$file
done
for file in $(/usr/bin/find . -type f -follow -mount) ; do
    /bin/ln -fd $TEMPLATE_DIR/dev/$file $DEST_DIR/dev/$file 2>/dev/null
done

#-----------------------------------------------------------------------------
#                                  /etc
#-----------------------------------------------------------------------------

echo -n " /etc "
cd $TEMPLATE_DIR/etc
for directory in $(/usr/bin/find . -not -name '.' -type d) ; do
    /bin/mkdir $DEST_DIR/etc/$directory
done
for file in $(/usr/bin/find . -type f -follow) ; do
    /bin/ln -f $TEMPLATE_DIR/etc/$file $DEST_DIR/etc/$file
done

#-----------------------------------------------------------------------------
#                                  /lib
#-----------------------------------------------------------------------------

echo -n " /lib "
cd $TEMPLATE_DIR/lib
for file in $(/usr/bin/find . -type f -follow -maxdepth 1) ; do
    /bin/ln -f $TEMPLATE_DIR/lib/$file $DEST_DIR/lib/$file
done

#-----------------------------------------------------------------------------
#                                 /root
#-----------------------------------------------------------------------------

echo -n " /root "
cd $TEMPLATE_DIR/root
for file in $(/usr/bin/find . -type f -maxdepth 1) ; do
    /bin/ln -f $TEMPLATE_DIR/root/$file $DEST_DIR/root/$file
done

#-----------------------------------------------------------------------------
#                                 /sbin
#-----------------------------------------------------------------------------
echo -n " /sbin "
cd $TEMPLATE_DIR/sbin
for directory in $(/usr/bin/find . -not -name '.' -type d -follow) ; do
    /bin/mkdir $DEST_DIR/sbin/$directory
done
for file in $(/usr/bin/find . -type f  -follow) ; do
    /bin/ln -f $TEMPLATE_DIR/sbin/$file $DEST_DIR/sbin/$file
done

#-----------------------------------------------------------------------------
#                                  /var
#-----------------------------------------------------------------------------

echo -n " /var "
cd $TEMPLATE_DIR/var
for directory in $(/usr/bin/find . -not -name '.' -type d -follow) ; do
    /bin/mkdir $DEST_DIR/var/$directory
done
for file in $(/usr/bin/find . -type f -follow -mount) ; do
    /bin/ln $TEMPLATE_DIR/var/$file $DEST_DIR/var/$file 
done

#-----------------------------------------------------------------------------
# Now we create network configuration files for the node
# First we remove all existing configuration scripts
#-----------------------------------------------------------------------------

echo -e "\nCreating network scripts ..."

# clean up ...
/bin/rm -f $DEST_DIR/etc/sysconfig/network 
/bin/rm -f $DEST_DIR/etc/sysconfig/network-scripts/ifcfg-eth* 

# /etc/HOSTNAME
echo "$HOST.$DOMAIN" > $DEST_DIR/etc/HOSTNAME

# create client's /etc/sysconfig/network
echo "NETWORKING=yes" \
    >> $DEST_DIR/etc/sysconfig/network 
echo "HOSTNAME=$HOST.$DOMAIN" \
    >> $DEST_DIR/etc/sysconfig/network 
echo "DOMAINNAME=$DOMAIN" \
    >> $DEST_DIR/etc/sysconfig/network 
echo "GATEWAY=$GATEWAY" \
    >> $DEST_DIR/etc/sysconfig/network 
echo "GATEWAYDEV=eth0" \
    >> $DEST_DIR/etc/sysconfig/network 

#-----------------------------------------------------------------------------
# create client's /etc/sysconfig/network-scripts/ifcfg-eth0
# if you have more than one interface per node you will have
# to add/change script 
#-----------------------------------------------------------------------------
 
echo "DEVICE=eth0" \
    >> $DEST_DIR/etc/sysconfig/network-scripts/ifcfg-eth0 
echo "IPADDR=$IPADDR" \
    >> $DEST_DIR/etc/sysconfig/network-scripts/ifcfg-eth0 
echo "NETMASK=$NETMASK" \
    >> $DEST_DIR/etc/sysconfig/network-scripts/ifcfg-eth0  
echo "NETWORK=$NETWORK" \
    >> $DEST_DIR/etc/sysconfig/network-scripts/ifcfg-eth0 
echo "BROADCAST=$BROADCAST" \
    >> $DEST_DIR/etc/sysconfig/network-scripts/ifcfg-eth0 
echo "ONBOOT=yes" \
    >> $DEST_DIR/etc/sysconfig/network-scripts/ifcfg-eth0 
echo "BOOTPROTO=none" \
    >> $DEST_DIR/etc/sysconfig/network-scripts/ifcfg-eth0 

#-----------------------------------------------------------------------------
# add the RARP entry
# Our server will use this to anwser client's RARP request and tell it
# it's IP address
#-----------------------------------------------------------------------------

/sbin/rarp -s $HOST $MACADDR

echo "/sbin/rarp -s $HOST $MACADDR" >> /etc/rc.d/init.d/rarp

#-----------------------------------------------------------------------------
# add the new machine to /etc/exports
#-----------------------------------------------------------------------------

echo "/tftpboot/$IPADDR/ $HOST.$DOMAIN (rw,no_all_squash,no_root_squash)" >> /etc/exports
echo "/usr  $HOST.$DOMAIN (rw,no_all_squash,no_root_squash)" >> /etc/exports
echo "/bin  $HOST.$DOMAIN (rw,no_all_squash,no_root_squash)" >> /etc/exports
echo "/sbin $HOST.$DOMAIN (rw,no_all_squash,no_root_squash)" >> /etc/exports
echo "/lib  $HOST.$DOMAIN (rw,no_all_squash,no_root_squash)" >> /etc/exports
echo "/home $HOST.$DOMAIN (rw,no_all_squash,no_root_squash)" >> /etc/exports

# restart the nfsd and mountd daemons on the server

/usr/bin/killall -HUP rpc.nfsd
/usr/bin/killall -HUP rpc.mountd

# create /etc/fstab entry

/bin/rm -f $DEST_DIR/etc/fstab

echo "$SERVER:/tftpboot/$IPADDR / nfs hard,intr,rw" >> $DEST_DIR/etc/fstab
echo "$SERVER:/usr  /usr nfs soft,intr,rw"   >> $DEST_DIR/etc/fstab
echo "$SERVER:/bin  /bin nfs soft,intr,rw"   >> $DEST_DIR/etc/fstab
echo "$SERVER:/sbin /sbin nfs soft,intr,rw"  >> $DEST_DIR/etc/fstab
echo "$SERVER:/lib  /lib nfs soft,intr,rw"   >> $DEST_DIR/etc/fstab
echo "$SERVER:/home /home nfs hard,intr,rw"  >> $DEST_DIR/etc/fstab

/bin/rm -f $DEST_DIR/etc/mtab
/bin/touch $DEST_DIR/etc/mtab

# some other files have to be unique for each client


/bin/rm -f $DEST_DIR/var/log/wtmp*
/bin/touch $DEST_DIR/var/log/wtmp

/bin/rm -f $DEST_DIR/var/log/lastlog*
/bin/touch $DEST_DIR/var/log/lastlog



echo "Done."


Next Previous Contents