#!/bin/bash # # Copyright (C) 2012 Google Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. set -e -u -o pipefail shopt -s extglob readonly self=$(readlink -f $0) readonly ensure_dirs=@PKGLIBDIR@/ensure-dirs readonly action_shortcuts=( start stop restart status watcher ) readonly default_nodecount=5 readonly default_instcount=10 readonly default_netprefix=192.0.2 readonly default_netdev=eth0 readonly default_initscript=@SYSCONFDIR@/init.d/ganeti readonly cluster_name=cluster readonly etc_hosts_filename=/etc/hosts # IP address space: # Cluster: .1 # Nodes: .10-.99 # Instances: .100-.254 readonly first_node_ipaddr_octet=10 readonly first_inst_ipaddr_octet=100 readonly max_node_count=$((first_inst_ipaddr_octet - first_node_ipaddr_octet)) readonly max_instance_count=$((255 - first_inst_ipaddr_octet)) usage() { echo "Usage: $0 [-E] [-N] [-c ] [-i ] [-p ]"\ '[-n ] [-I ] ' echo echo 'Options:' echo " -c Number of virtual nodes (defaults to $default_nodecount)" echo " -i Number of instances (defaults to $default_instcount)" echo " -p IPv4 network prefix (defaults to $default_netprefix)" echo ' -n Network device for virtual IP addresses (defaults to'\ "$default_netdev)" echo " -I Path to init script (defaults to $default_initscript)" echo " -E Do not modify $etc_hosts_filename" echo ' -N Do not configure networking' } # Variables for options nodecount=$default_nodecount instcount=$default_instcount netprefix=$default_netprefix netdev=$default_netdev initscript=$default_initscript etchosts=1 networking=1 # Parse options while getopts :hENc:p:n:i:I: opt; do case "$opt" in h) usage exit 0 ;; c) nodecount="$OPTARG" if [[ "$nodecount" != +([0-9]) ]]; then echo "Invalid node count number: $nodecount" >&2 exit 1 elif (( nodecount > max_node_count )); then echo "Node count must be $max_node_count or lower" >&2 exit 1 fi ;; i) instcount="$OPTARG" if [[ "$instcount" != +([0-9]) ]]; then echo "Invalid instance count number: $instcount" >&2 exit 1 elif (( instcount > max_instance_count )); then echo "Instance count must be $max_instance_count or lower" >&2 exit 1 fi ;; p) netprefix="$OPTARG" if [[ "$netprefix" != +([0-9]).+([0-9]).+([0-9]) ]]; then echo "Invalid network prefix: $netprefix" >&2 exit 1 fi ;; n) netdev="$OPTARG" if ! ip link show $netdev >/dev/null; then echo "Invalid network device: $netdev" >&2 exit 1 fi ;; I) initscript="$OPTARG" if [[ ! -x $initscript ]]; then echo "Init script '$initscript' is not executable" >&2 exit 1 fi ;; E) etchosts= ;; N) networking= ;; \?) echo "Invalid option: -$OPTARG" >&2 usage >&2 exit 1 ;; :) echo "Option -$OPTARG requires an argument" >&2 usage >&2 exit 1 ;; esac done shift $((OPTIND - 1)) if [[ "$#" != 1 ]]; then usage exit 1 fi readonly rootdir=$1; shift if [[ ! -d "$rootdir" ]]; then echo "Directory '$rootdir' does not exist!" >&2 exit 1 fi if (( $nodecount < 1 )); then echo "Must create at least one node, currently requested $nodecount" >&2 exit 1 fi node_hostname() { local -r number="$1" echo "node$((number + 1))" } instance_hostname() { local -r number="$1" echo "instance$((number + 1))" } node_ipaddr() { local -r number="$1" echo "$netprefix.$((first_node_ipaddr_octet + number))" } instance_ipaddr() { local -r number="$1" echo "$netprefix.$((first_inst_ipaddr_octet + number))" } setup_node() { local -r number="$1" local -r nodedir=$rootdir/$(node_hostname $number) echo "Setting up node '$(node_hostname $number)' ..." >&2 if [[ ! -d $nodedir ]]; then mkdir $nodedir fi mkdir -p \ $nodedir@SYSCONFDIR@/{default,ganeti} \ $nodedir@LOCALSTATEDIR@/lock\ $nodedir@LOCALSTATEDIR@/{lib,log,run}/ganeti GANETI_HOSTNAME=$(node_hostname $number) \ GANETI_ROOTDIR=$nodedir \ $ensure_dirs local -r daemon_args="-b $(node_ipaddr $number)" cat > $nodedir/etc/default/ganeti < $nodedir/cmd <&2 ( set -e -u local -r tmpfile=$(mktemp $etc_hosts_filename.vcluster.XXXXX) trap "rm -f $tmpfile" EXIT { egrep -v "^$netprefix.[[:digit:]]+[[:space:]]" $etc_hosts_filename echo "$netprefix.1 $cluster_name" for ((i=0; i < nodecount; ++i)); do echo "$(node_ipaddr $i) $(node_hostname $i)" done for ((i=0; i < instcount; ++i)); do echo "$(instance_ipaddr $i) $(instance_hostname $i)" done } > $tmpfile && \ chmod 0644 $tmpfile && \ mv $tmpfile $etc_hosts_filename && \ trap - EXIT ) } setup_network_interfaces() { echo 'Configuring network ...' >&2 for ((i=0; i < nodecount; ++i)); do local ipaddr="$(node_ipaddr $i)/32" ip addr del "$ipaddr" dev "$netdev" || : ip addr add "$ipaddr" dev "$netdev" done route add -net $netprefix.0 netmask 255.255.255.0 dev $netdev || : } setup_scripts() { echo 'Configuring helper scripts ...' >&2 for action in "${action_shortcuts[@]}"; do { echo '#!/bin/bash' for ((i=0; i < nodecount; ++i)); do local name=$(node_hostname $i) if [[ $action = watcher ]]; then echo "echo 'Running watcher for virtual node \"$name\" ..." echo "$name/cmd ganeti-watcher \"\$@\"" else echo "echo 'Action \"$action\" for virtual node \"$name\" ...'" echo "$name/cmd $initscript $action \"\$@\"" fi done } > $rootdir/$action-all chmod +x $rootdir/$action-all done } show_info() { cat <