installdir="`dirname \"$autocluster\"`"
fi
-config="config"
-
-# catch errors
-set -e
-set -E
-trap 'es=$?;
- echo ERROR: failed in function \"${FUNCNAME}\" at line ${LINENO} of ${BASH_SOURCE[0]} with code $es;
- exit $es' ERR
-
####################
# show program usage
usage ()
Usage: autocluster [OPTION] ... <COMMAND>
options:
-c <file> specify config file (default is "config")
- --firstip N override FIRSTIP from config
- -n don't create a TSM node
-x enable script debugging
+ --dump dump config settings and exit
+
+ configuration options:
+EOF
+
+ usage_config_options
+
+ cat >&2 <<EOF
commands:
create base
create_node "$CLUSTER" $i
done
- if [ $withtsmnode -eq 1 ]; then
+ if [ $WITH_TSM_NODE -eq 1 ]; then
echo "Creating TSM server node"
create_tsm "$CLUSTER"
fi
echo "# autocluster $CLUSTER" > hosts.$CLUSTER
- [ $withtsmnode -eq 1 ] && {
+ [ $WITH_TSM_NODE -eq 1 ] && {
echo "$IPBASE.0.$FIRSTIP ${CLUSTER}tsm.$LOWDOMAIN ${CLUSTER}tsm" >> hosts.$CLUSTER
}
for i in `seq 1 $NUMNODES`; do
######################################################################
+. "$installdir/functions"
+. "$installdir/config.default"
############################
# parse command line options
-temp=$(getopt -n "$prog" -o "c:xhn" -l help,firstip: -- "$@")
-
+long_opts=$(getopt_config_options)
+getopt_output=$(getopt -n autocluster -o "c:xh" -l help,dump -l "$long_opts" -- "$@")
[ $? != 0 ] && usage
-eval set -- "$temp"
+use_default_config=true
-withtsmnode=1
+# We 2 passes of the options. The first time we just handle usageor the first pass
+eval set -- "$getopt_output"
+while true ; do
+ case "$1" in
+ -c) shift 2 ; use_default_config=false ;;
+ --) shift ; break ;;
+ --dump|-x) shift ;;
+ -h|--help) usage ;; # Usage should be shown here for real defaults.
+ --*) shift 2 ;; # Assume other long opts are valid and take an arg.
+ *) usage ;; # shouldn't happen, so this is reasonable.
+ esac
+done
+
+config="./config"
+$use_default_config && [ -r "$config" ] && . "$config"
+
+eval set -- "$getopt_output"
while true ; do
case "$1" in
- -c) config="$2" ; shift; shift ;;
- --firstip) firstip="$2"; shift; shift; ;;
- -n) withtsmnode=0; shift; ;;
+ -c) . "`dirname $2`/$2" ; shift 2 ; conf_done=true ;;
-x) set -x; shift ;;
+ --dump) dump_config ;;
--) shift ; break ;;
- -h|--help|*) usage ;; # Shouldn't happen, so this is reasonable.
+ -h|--help) usage ;; # Redundant.
+ --*)
+ # Putting --opt1|opt2|... into a variable and having case
+ # match against it as a pattern doesn't work. The | is
+ # part of shell syntax, so we need to do this. Look away
+ # now to stop your eyes from bleeding! :-)
+ x=",${long_opts}" # Now each option is surrounded by , and :
+ if [ "$x" != "${x#*,${1#--}:}" ] ; then
+ # Our option, $1, surrounded by , and : was in $x, so is legal.
+ setconf_longopt "$1" "$2"; shift 2
+ else
+ usage
+ fi
+ ;;
+ *) usage ;; # shouldn't happen, so this is reasonable.
esac
done
-. "$installdir/config.default"
-. "`dirname $config`/$config"
-. "$installdir/functions"
-
-[ -n "$firstip" ] && {
- FIRSTIP="$firstip"
-}
+# catch errors
+set -e
+set -E
+trap 'es=$?;
+ echo ERROR: failed in function \"${FUNCNAME}\" at line ${LINENO} of ${BASH_SOURCE[0]} with code $es;
+ exit $es' ERR
LOWDOMAIN=`echo $DOMAIN | tr A-Z a-z`
# please override with your own options in your own config file
# where virtual machines are stored on this host
-VIRTBASE=/virtual
+defconf VIRTBASE /virtual \
+ "<path>" "virtual machine directory for this host"
# where to find virsh
-VIRSH="virsh -c qemu:///system"
+defconf VIRSH "virsh -c qemu:///system" \
+ "<cmd>" "how to invoke virsh"
# the name of the base RHEL install image that the nodes will be based on
# a kvm image called $VIRTBASE/$BASENAME.img will be created
# that will form the basis file for the images for each of the nodes
-BASENAME="SoFS-1.5-base"
+defconf BASENAME "SoFS-1.5-base" \
+ "<file>" "filename for cluster base image"
# the install server where we will get SoFS packages from
-INSTALL_SERVER="http://9.155.61.11/mediasets"
+defconf INSTALL_SERVER "http://9.155.61.11/mediasets" \
+ "<url>" "URL of install server"
# what timezone to put the nodes in
# leave this empty to base the timezone on the zone that
# this host is in
-TIMEZONE=
+defconf TIMEZONE "" \
+ "<tz>" "timezone for each node"
# what keyboard type to setup
-KEYBOARD="us"
+defconf KEYBOARD "us" \
+ "<kbd>" "keyboard layout for each node"
# the base ISO to install from
-ISO="/virtual/ISO/RHEL5.2-Server-20080430.0-x86_64-DVD.iso"
+defconf ISO "/virtual/ISO/RHEL5.2-Server-20080430.0-x86_64-DVD.iso" \
+ "<file>" "location of ISO image for base image creation"
# which template kickstart file to use. There are separate templates
# for each version of SoFS
-KICKSTART="$installdir/templates/kickstart-1.5.cfg"
+defconf KICKSTART "$installdir/templates/kickstart-1.5.cfg" \
+ "<file>" "choice of kickstart file"
# the yum repositories to use. Choose the one appropriate for the
# version of SoFS you are installing
-YUM_TEMPLATE="$installdir/templates/SoFS-1.5.repo"
-
+defconf YUM_TEMPLATE "$installdir/templates/SoFS-1.5.repo" \
+ "<file>" "location of template for yum repositories"
# any extra packages to install. List one on each line. To force a package
# not to be installed, list it with a leading -
-EXTRA_PACKAGES='
+defconf EXTRA_PACKAGES '
emacs
-'
+' \
+ "<list>" "extra packages for kickstart to install"
# RHEL install key
-INSTALLKEY="--skip"
+defconf INSTALLKEY "--skip" \
+ "<key>" "RHEL install key"
# the kvm binary to use - should be a very recent version
# I am using a git snapshot from http://kvm.qumranet.com/kvmwiki/Code
-KVM="/usr/local/bin/qemu-system-x86_64"
+defconf KVM "/usr/local/bin/qemu-system-x86_64" \
+ "<file>" "location of KVM executable"
# memory for each node
-MEM=250000
+defconf MEM 250000 \
+ "<n>" "memory allocated for each node"
# memory for the node that will run the SoFS GUI - used if it is
# greater than $MEM
-GUIMEM=700000
+defconf GUIMEM 700000 \
+ "<n>" "memory allocated for the management node"
# a directory on the host which will be mounted via NFS onto the
# nodes as /root/SOFS, giving a nice common area independent of GPFS
# This is useful for compiles, RPMs, devel scripts etc
# you need to add this to your /etc/exports and run exportfs -av yourself
# on the host
-NFSSHARE="10.0.0.1:/home/SOFS"
+defconf NFSSHARE "10.0.0.1:/home/SOFS" \
+ "<mnt>" "NFS share to mount on each node"
# windows domain name the nodes will be part of
-DOMAIN="VSOFS1.COM"
+defconf DOMAIN "VSOFS1.COM" \
+ "<dom>" "Windows(TM) domain name for each node"
# windows workgroup name the nodes will be part of
-WORKGROUP="VSOFS1"
+defconf WORKGROUP "VSOFS1" \
+ "<grp>" "Windows(TM) workgroup for node"
# DNS name server. Usually set this to the
# kvm host, then setup DNS on the kvm host to direct
# queries for the windows domain name to the w2003 server
-NAMESERVER="10.0.0.1"
+defconf NAMESERVER "10.0.0.1" \
+ "<ip>" "DNS server for each node"
# any extra domains to add to the search list
-DNSSEARCH="$DOMAIN"
+defconf DNSSEARCH "$DOMAIN" \
+ "<dom>" "extra domains for DNS search list"
# set the first two octets of the IPs we will use
# the 3rd and 4th octets are controlled by the node setup scripts
-IPBASE="10.0"
+defconf IPBASE "10.0" \
+ "<n>.<n>" "first 2 octets of IP for each node"
+
+# should we create a TSM node? If this is not 1 then no TSM node is
+# created and all other TSM options are ignored.
+defconf WITH_TSM_NODE 1 \
+ "<0|1>" "1 if a TSM node should be created"
# the nodes will get IPs starting at this number
# the TSM server will get $FIRSTIP, then the first node will get
# 1st node 10.0.0.21
# 2nd node 10.0.0.22
# etc etc
-FIRSTIP="20"
+defconf FIRSTIP "20" \
+ "<n>" "final octet for the 1st IP of the cluster"
# a caching web proxy that can get to the install server from the
# nodes. If you don't have one on the local network then look in
# several G of cache You can choose to have no web proxy at all, in
# which case set it to the empty string, and hope you have a fast
# network connection to the install server
-WEBPROXY="http://10.0.0.1:3128/"
+defconf WEBPROXY "http://10.0.0.1:3128/" \
+ "<url>" "URL of a caching web proxy"
# IP gateway (the IP of the kvm host for the clients)
-GATEWAY="10.0.0.1"
+defconf GATEWAY "10.0.0.1" \
+ "<ip>" "IP gateway for cluster hosts, usually KVM host"
# how many nodes to build
# this doesn't include the TSM server
-NUMNODES=4
+defconf NUMNODES 4 \
+ "<n>" "number of nodes to build, not including TSM server"
# how much disk space to use on each node
# note that it will only use what is actually occupied,
# so start this larger than you think you'll need
-DISKSIZE="20G"
+defconf DISKSIZE "20G" \
+ "<n>G" "maximum disk size for each node"
# size of root partition in megabytes
-ROOTSIZE=15000
+defconf ROOTSIZE 15000 \
+ "<n>" "size of root partition in MB"
# size of swap partition in megabytes
-SWAPSIZE=2000
+defconf SWAPSIZE 2000 \
+ "<n>" "size of swap partition in MB"
# the size of the 3 GPFS shared disks
-SHAREDDISKSIZE="10G"
+defconf SHAREDDISKSIZE "10G" \
+ "<n>G" "size of the 3 GPFS shared disks"
# the size of the TSM storage disk
-TSMDISKSIZE="50G"
+defconf TSMDISKSIZE "50G" \
+ "<n>G" "size of the TSM storage disk"
# what network adapter to use
-NICMODEL="e1000"
+defconf NICMODEL "e1000" \
+ "<module>" "choice of KVM network adapter"
# where we will log serial consoles to
-KVMLOG="/var/log/kvm"
+defconf KVMLOG "/var/log/kvm" \
+ "<dir>" "directory for serial logs"
# initial root password
-ROOTPASSWORD="password"
+defconf ROOTPASSWORD "password" \
+ "<string>" "initial root password for each node"
# install language - make it the same as the installers by default
-LANGUAGE="${LANG:-en_US.UTF-8}"
+defconf LANGUAGE "${LANG:-en_US.UTF-8}" \
+ "<locale>" "locale for installer to use"
# name of the system in CIFS protocol
-CIFSNAME="Samba01"
+defconf CIFSNAME "Samba01" \
+ "<name>" "name of the system in CIFS protocol"
# the name that the nodes will use to talk to the TSM server
-TSMNAME="SOFS01"
+defconf TSMNAME "SOFS01" \
+ "<name>" "name used by nodes to talk to TSM server"
# how big should the TSM database be
-TSM_DB_SIZE=100
+defconf TSM_DB_SIZE 100 \
+ "<n>" "size of TSM database"
# how big should the TSM space management pool be
-TSM_SPACE_MGMT_SIZE=1024
+defconf TSM_SPACE_MGMT_SIZE 1024 \
+ "<n>" "size of TSM space management pool"
# how big should the TSM backup pool be
-TSM_BACKUP_POOL_SIZE=100
+defconf TSM_BACKUP_POOL_SIZE 100 \
+ "<n>" "size of TSM backup pool"
# how big should the TSM archive pool be
-TSM_ACRHIVE_POOL_SIZE=100
+defconf TSM_ACRHIVE_POOL_SIZE 100 \
+ "<n>" "size of TSM archive pool"
# the min size of the java heap for the SoFS GUI
-JAVA_MIN_SIZE="200M"
+defconf JAVA_MIN_SIZE "200M" \
+ "<n>M" "minimum size of Java heap for SoFS GUI"
# the max size of the java heap for the SoFS GUI
-JAVA_MAX_SIZE="400M"
+defconf JAVA_MAX_SIZE "400M" \
+ "<n>M" "maximum size of Java heap for SoFS GUI"
# how many virtual CPUs per node?
-NUMCPUS=2
+defconf NUMCPUS 2 \
+ "<n>" "number of virtual CPUs per node"
# libvirt template to use for nodes
-NODE_TEMPLATE="$installdir/templates/node.xml"
+defconf NODE_TEMPLATE "$installdir/templates/node.xml" \
+ "<file>" "libvirt template for nodes"
# libvirt template to use for TSM server
-TSM_TEMPLATE="$installdir/templates/tsmserver.xml"
+defconf TSM_TEMPLATE "$installdir/templates/tsmserver.xml" \
+ "<file>" "libvirt template for TSM server"
# libvirt template to use for initial install
-INSTALL_TEMPLATE="$installdir/templates/install.xml"
+defconf INSTALL_TEMPLATE "$installdir/templates/install.xml" \
+ "<file>" "libvirt template for initial install"
# libvirt template to use for boot_base.sh
-BOOT_TEMPLATE="$installdir/templates/bootbase.xml"
+defconf BOOT_TEMPLATE "$installdir/templates/bootbase.xml" \
+ "<file>" "libvirt template for \"bootbase\" command"
# where to get the base templates from
-BASE_TEMPLATES="$installdir/base"
+defconf BASE_TEMPLATES "$installdir/base" \
+ "<dir>" "directory containing base templates"
# nbd device to use
-NBD_DEVICE="/dev/nbd0"
+defconf NBD_DEVICE "/dev/nbd0" \
+ "<dev>" "NBD device node to use"
-# the format to use the for qemu base images
-BASE_FORMAT="qcow2"
+# the format to use for qemu base images
+defconf BASE_FORMAT "qcow2" \
+ "<fmt>" "format to use for the qemu base images"
-# common functions for autocluster
+# common functions for autocluster (-*- shell-script -*-)
# create a MAC address based on a hash of the cluster name
# plus the adapter and node number
fi
}
+# Set a variable if it isn't already set. This allows environment
+# variables to override default config settings.
+defconf() {
+ local v="$1"
+ local e="$2"
+
+ [ "${!v+x}" ] || eval "$v=\"$e\""
+}
+
+# Print the list of config variables defined in config.default.
+get_config_options() {( # sub-shell for local declaration of defconf()
+ local options=
+ defconf() { options="$options $1" ; }
+ . "$installdir/config.default"
+ echo $options
+)}
+
+# Produce a list of long options, suitable for use with getopt, that
+# represent the config variables defined in config.default.
+getopt_config_options() {
+ local x=$(get_config_options | tr 'A-Z_' 'a-z-')
+ echo "${x// /:,}:"
+}
+
+# Unconditionally set the config variable associated with the given
+# long option.
+setconf_longopt() {
+ local longopt="$1"
+ local e="$2"
+
+ local v=$(echo "${longopt#--}" | tr 'a-z-' 'A-Z_')
+ # unset so defconf will set it
+ eval "unset $v"
+ defconf "$v" "$e"
+}
+
+# Dump all of the current config variables.
+dump_config() {
+ local o
+ for o in $(get_config_options) ; do
+ echo "${o}=\"${!o}\""
+ done
+ exit 0
+}
+
+# Print text assuming it starts after other text in $startcol and
+# needs to wrap before $fillcol. Subsequent lines start at $startcol.
+# Long "words" will extend past $fillcol.
+fill_text() {
+ local startcol="$1"
+ local fillcol="$2"
+ local text="$3"
+
+ local width=$(($fillcol - $startcol))
+ [ $width -lt 0 ] && width=$((78 - $startcol))
+
+ local out=""
+
+ local padding=$(printf "\n%${startcol}s" " ")
+
+ while [ -n "$text" ] ; do
+ local orig="$text"
+
+ # If we already have output then arrange padding on the next line.
+ [ -n "$out" ] && out="${out}${padding}"
+
+ # Break the text at $width.
+ out="${out}${text:0:${width}}"
+ text="${text:${width}}"
+
+ # If we have left over text then the line break may be ugly,
+ # so let's check and try to break it on a space.
+ if [ -n "$text" ] ; then
+ if [ "${text:0:1}" != " " -a "${text: -1:1}" != " " ] ; then
+ # We didn't break on a space. Arrange for the
+ # beginning of the broken "word" to appear on the next
+ # line but not if it will make us loop infinitely.
+ if [ "${orig}" != "${out##* }${text}" ] ; then
+ text="${out##* }${text}"
+ out="${out% *}"
+ else
+ # Hmmm, doing that would make us loop, so add the
+ # rest of the word from the remainder of the text
+ # to this line and let it extend past $fillcol.
+ out="${out}${text%% *}"
+ if [ "${text# *}" != "$text" ] ; then
+ # Remember the text after the next space for next time.
+ text="${text# *}"
+ else
+ # No text after next space.
+ text=""
+ fi
+ fi
+ else
+ # We broke on a space. If it will be at the beginning
+ # of the next line then remove it.
+ text="${text# }"
+ fi
+ fi
+ done
+
+ echo "$out"
+}
+
+# Display usage text, trying these approaches in order.
+# 1. See if it all fits on one line before $fillcol.
+# 2. See if splitting before the default value and indenting it
+# to $startcol means that nothing passes $fillcol.
+# 3. Treat the message and default value as a string and just us fill_text()
+# to format it.
+usage_display_text() {
+ local startcol="$1"
+ local fillcol="$2"
+ local desc="$3"
+ local default="$4"
+
+ local width=$(($fillcol - $startcol))
+
+ # To avoid clutter, only quote values that need it.
+ #local q=
+ #[ -z "$default" -o "$(echo $default)" = "${default// /}" ] || q="\""
+ default="(default \"$default\")"
+
+ if [ $((${#desc} + 1 + ${#default})) -le $width ] ; then
+ echo "${desc} ${default}"
+ else
+ local padding=$(printf "%${startcol}s" " ")
+
+ if [ ${#desc} -lt $width -a ${#default} -lt $width ] ; then
+ echo "$desc"
+ echo "${padding}${default}"
+ else
+ fill_text $startcol $fillcol "${desc} ${default}"
+ fi
+ fi
+}
+
+# Display usage information for long config options.
+usage_config_options(){( # sub-shell for local declaration of defconf()
+ local def_fillcol=78
+ local fillcol=$def_fillcol
+ local rows=$(stty size | sed -e 's@.* @@')
+ [ -n "$rows" ] && fillcol=$(($rows - 2))
+
+ local startcol=33
+
+ # We need to have at least one column... negative is also a problem.
+ [ $fillcol -le $startcol ] && fillcol=$def_fillcol
+
+ defconf() {
+ local local longopt=$(echo "$1" | tr 'A-Z_' 'a-z-')
+
+ printf " --%-25s " "${longopt}=${3}" >&2
+
+ usage_display_text $startcol $fillcol "$4" "$2" >&2
+ }
+ . "$installdir/config.default"
+)}