summaryrefslogtreecommitdiffstats
path: root/tools/cluster-init.in
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xtools/cluster-init.in537
1 files changed, 537 insertions, 0 deletions
diff --git a/tools/cluster-init.in b/tools/cluster-init.in
new file mode 100755
index 0000000..1485c81
--- /dev/null
+++ b/tools/cluster-init.in
@@ -0,0 +1,537 @@
+#!@BASH_PATH@
+#
+# Copyright 2011-2023 the Pacemaker project contributors
+#
+# The version control history for this file may have further details.
+#
+# This source code is licensed under the GNU General Public License version 2
+# or later (GPLv2+) WITHOUT ANY WARRANTY.
+#
+
+accept_defaults=0
+do_raw=0
+ETCHOSTS=0
+nodelist=0
+limit=0
+
+pkgs="corosync xinetd nmap abrt-cli fence-agents perl-TimeDate gdb"
+
+transport="multicast"
+inaddr_any="no"
+
+INSTALL=
+cs_conf=
+fence_conf=
+
+dsh_group=0
+if [ ! -z $cluster_name ]; then
+ cluster=$cluster_name
+else
+ cluster=dummy0
+fi
+
+# Corosync Settings
+cs_port=666
+
+# Settings that work great on nXX
+join=60
+#token=3000
+consensus=1500
+
+# Official settings
+join=2000
+token=5000
+consensus=2500
+
+# Testing
+join=1000
+consensus=7500
+do_debug=off
+
+function ip_for_node() {
+ ping -c 1 $1 | grep "bytes from" | head -n 1 | sed -e 's/.*bytes from//' -e 's/: icmp.*//' | awk '{print $NF}' | sed 's:(::' | sed 's:)::'
+# if [ $do_raw = 1 ]; then
+# echo $1
+# else
+# #host $1 | grep "has address" | head -n 1 | awk '{print $NF}' | sed 's:(::' | sed 's:)::'
+# fi
+}
+function id_for_node() {
+ ip_for_node $* | tr '.' ' ' | awk '{print $4}'
+}
+function name_for_node() {
+ echo $1 | awk -F. '{print $1}'
+}
+
+function helptext() {
+ echo "cluster-init - Configure cluster communication for the infrastructures supported by Pacemaker"
+ echo ""
+ echo "-g, --group Specify the group to operate on/with"
+ echo "-w, --host Specify a host to operate on/with. May be specified multiple times"
+ echo "-r, --raw-ip Supplied nodes were listed as their IP addresses"
+ echo ""
+ echo "-c, --corosync configure for corosync"
+ echo "-C, --nodelist configure for corosync with a node list"
+ echo "-u, --unicast configure point-to-point communication instead of multicast"
+ echo ""
+ echo "-I, --install Install packages"
+ echo ""
+ echo "-d, --debug Enable debug logging for the cluster"
+ echo "--hosts Copy the local /etc/hosts file to all nodes"
+ echo "-e, --extra list Whitespace separated list of extra packages to install"
+ echo "-l, --limit N Use the first N hosts from the named group"
+ echo " Extra packages to install"
+ exit $1
+}
+
+host_input=""
+while true; do
+ case "$1" in
+ -g) cluster=$2;
+ shift; shift;;
+ -w|--host)
+ for h in $2; do
+ host_input="$host_input -w $h";
+ done
+ shift; shift;;
+ -w) host_input="$host_input -w $2"
+ shift; shift;;
+ -r|--raw-ip) do_raw=1; shift;;
+
+ -d|--debug) do_debug=on; shift;;
+
+ -I|--install) INSTALL=Yes; shift;;
+ --hosts) ETCHOSTS=1; shift;;
+
+ -c|--corosync) CTYPE=corosync; shift;;
+ -C|--nodelist) CTYPE=corosync; nodelist=1; shift;;
+ -u|--unicast) nodelist=1; transport=udpu; inaddr_any="yes"; shift;;
+ -e|--extra) pkgs="$pkgs $2"; shift; shift;;
+ -t|--test) pkgs="$pkgs valgrind"; shift;;
+ -l|--limit) limit=$2; shift; shift;;
+
+ r*[0-9])
+ rhel=`echo $1 | sed -e s/rhel// -e s/-// -e s/r//`
+ pkgs="$pkgs qarsh-server";
+ case $rhel in
+ 7) CTYPE=corosync;;
+ esac
+ shift
+ ;;
+
+ f*[0-9][0-9])
+ CTYPE=corosync;
+ shift
+ ;;
+
+ -y|--yes|--defaults) accept_defaults=1; shift;;
+ -x) set -x; shift;;
+ -\?|--help) helptext 0; shift;;
+ "") break;;
+ *) echo "unknown option: $1"; exit 1;;
+ esac
+done
+
+if [ ! -z $cluster ]; then
+ host_input="-g $cluster"
+ # use the last digit present in the variable (if any)
+ dsh_group=`echo $cluster | sed 's/[^0-9][^0-9]*//g;s/.*\([0-9]\)$/\1/'`
+fi
+
+if [ -z $dsh_group ]; then
+ dsh_group=1
+fi
+
+if [ x = "x$host_input" -a x = "x$cluster" ]; then
+ if [ -d $HOME/.dsh/group ]; then
+ read -p "Please specify a dsh group you'd like to configure as a cluster? [] " -t 60 cluster
+ else
+ read -p "Please specify a whitespace delimetered list of nodes you'd like to configure as a cluster? [] " -t 60 host_list
+
+ for h in $2; do
+ host_input="$host_input -w $h";
+ done
+ fi
+fi
+
+if [ -z "$host_input" ]; then
+ echo "You didn't specify any nodes or groups to configure"
+ exit 1
+fi
+
+if [ $limit -gt 0 ]; then
+ echo "Using only the first $limit hosts in $cluster group"
+ host_list=`cluster-helper --list bullet $host_input | head -n $limit | tr '\n*' ' '`
+else
+ host_list=`cluster-helper --list short $host_input`
+fi
+num_hosts=`echo $host_list | wc -w`
+
+if [ $num_hosts -gt 9 ]; then
+ cs_port=66
+fi
+
+for h in $host_list; do
+ ping -c 1 -q $h
+ if [ $? != 0 ]; then
+ echo "Using long names..."
+ host_list=`cluster-helper --list long $host_input`
+ break
+ fi
+done
+
+if [ -z $CTYPE ]; then
+ echo ""
+ read -p "Where should Pacemaker obtain membership and quorum from? [corosync] (corosync) " -t 60 CTYPE
+fi
+
+case $CTYPE in
+ corosync) cs_conf="@PCMK__COROSYNC_CONF@" ;;
+esac
+
+function get_defaults()
+{
+ if [ -z $SSH ]; then
+ SSH="No"
+ fi
+
+ if [ -z $SELINUX ]; then
+ SELINUX="No"
+ fi
+
+ if [ -z $IPTABLES ]; then
+ IPTABLES="Yes"
+ fi
+
+ if [ -z $DOMAIN ]; then
+ DOMAIN="No"
+ fi
+ if [ -z $INSTALL ]; then
+ INSTALL="Yes"
+ fi
+ if [ -z $DATE ]; then
+ DATE="No"
+ fi
+}
+
+get_defaults
+if [ $accept_defaults = 0 ]; then
+ echo ""
+ read -p "Shall I install an ssh key to cluster nodes? [$SSH] " -t 60 SSH
+ echo ""
+ echo "SELinux prevent many things, including password-less ssh logins"
+ read -p "Shall I disable selinux? [$SELINUX] " -t 60 SELINUX
+ echo ""
+ echo "Incorrectly configured firewalls will prevent corosync from starting up"
+ read -p "Shall I disable iptables? [$IPTABLES] " -t 60 IPTABLES
+
+ echo ""
+ read -p "Shall I install/update the relevant packages? [$INSTALL] " -t 60 INSTALL
+
+ echo ""
+ read -p "Shall I sync the date/time? [$DATE] " -t 60 DATE
+fi
+get_defaults
+
+echo ""
+echo "Detecting possible fencing options"
+if [ -e /etc/cluster/fence_xvm.key ]; then
+ echo "* Found fence_xvm"
+ fence_conf=/etc/cluster/fence_xvm.key
+ pkgs="$pkgs fence-virt"
+fi
+
+if [ ! -z ${OS_AUTH_URL} ]; then
+ echo "* Found openstack credentials"
+ fence_conf=/sbin/fence_openstack
+ pkgs="$pkgs python-novaclient"
+fi
+echo ""
+echo "Beginning cluster configuration"
+echo ""
+
+case $SSH in
+ [Yy][Ee][Ss]|[Yy])
+ for host in $host_list; do
+ echo "Installing our ssh key on ${host}"
+ ssh-copy-id root@${host} >/dev/null 2>&1
+ # Fix selinux labeling
+ ssh -l root ${host} -- restorecon -R -v .
+ done
+ ;;
+esac
+
+case $DATE in
+ [Yy][Ee][Ss]|[Yy])
+ for host in $host_list; do
+ echo "Setting time on ${host}"
+ scp /etc/localtime root@${host}:/etc
+ now=`date +%s`
+ ssh -l root ${host} -- date -s @$now
+ echo ""
+ done
+ ;;
+esac
+
+init=`mktemp`
+cat<<-END>$init
+verbose=0
+pkgs="$pkgs"
+
+lhost=\`uname -n\`
+lshort=\`echo \$lhost | awk -F. '{print \$1}'\`
+
+log() {
+ printf "%-10s \$*\n" "\$lshort:" 1>&2
+}
+
+debug() {
+ if [ \$verbose -gt 0 ]; then
+ log "Debug: \$*"
+ fi
+}
+
+info() {
+ log "\$*"
+}
+
+warning() {
+ log "WARN: \$*"
+}
+
+fatal() {
+ log "ERROR: \$*"
+ exit 1
+}
+
+case $SELINUX in
+ [Yy][Ee][Ss]|[Yy])
+ sed -i.sed "s/enforcing/disabled/g" /etc/selinux/config
+ ;;
+esac
+
+case $IPTABLES in
+ [Yy][Ee][Ss]|[Yy]|"")
+ service iptables stop
+ chkconfig iptables off
+ service firewalld stop
+ chkconfig firewalld off
+ ;;
+esac
+
+case $DOMAIN in
+ [Nn][Oo]|"")
+ ;;
+ *.*)
+ if
+ ! grep domain /etc/resolv.conf
+ then
+ sed -i.sed "s/nameserver/domain\ $DOMAIN\\\nnameserver/g" /etc/resolv.conf
+ fi
+ ;;
+ *) echo "Unknown domain: $DOMAIN";;
+esac
+
+case $INSTALL in
+ [Yy][Ee][Ss]|[Yy]|"")
+ info Installing cluster software
+ yum install -y $pkgs pacemaker
+ ;;
+esac
+
+info "Configuring services"
+chkconfig xinetd on
+service xinetd start &>/dev/null
+
+chkconfig corosync off &> /dev/null
+mkdir -p /etc/cluster
+
+info "Turning on core files"
+grep -q "unlimited" /etc/bashrc
+if [ $? = 1 ]; then
+ sed -i.sed "s/bashrc/bashrc\\\nulimit\ -c\ unlimited/g" /etc/bashrc
+fi
+
+function patch_cs_config() {
+ test $num_hosts != 2
+ two_node=$?
+
+ priority="info"
+ if [ $do_debug = 1 ]; then
+ priority="debug"
+ fi
+
+ ssh -l root ${host} -- sed -i.sed "s/.*mcastaddr:.*/mcastaddr:\ 226.94.1.1/g" $cs_conf
+ ssh -l root ${host} -- sed -i.sed "s/.*mcastport:.*/mcastport:\ $cs_port$dsh_group/g" $cs_conf
+ ssh -l root ${host} -- sed -i.sed "s/.*bindnetaddr:.*/bindnetaddr:\ $ip/g" $cs_conf
+ ssh -l root ${host} -- sed -i.sed "s/.*syslog_facility:.*/syslog_facility:\ daemon/g" $cs_conf
+ ssh -l root ${host} -- sed -i.sed "s/.*logfile_priority:.*/logfile_priority:\ $priority/g" $cs_conf
+
+ if [ ! -z $token ]; then
+ ssh -l root ${host} -- sed -i.sed "s/.*token:.*/token:\ $token/g" $cs_conf
+ fi
+ if [ ! -z $consensus ]; then
+ ssh -l root ${host} -- sed -i.sed "s/.*consensus:.*/consensus:\ $consensus/g" $cs_conf
+ fi
+ if [ ! -z $join ]; then
+ ssh -l root ${host} -- sed -i.sed "s/^join:.*/join:\ $join/g" $cs_conf
+ ssh -l root ${host} -- sed -i.sed "s/\\\Wjoin:.*/join:\ $join/g" $cs_conf
+ fi
+
+ ssh -l root ${host} -- grep -q "corosync_votequorum" $cs_conf 2>&1 > /dev/null
+ if [ $? -eq 0 ]; then
+ ssh -l root ${host} -- sed -i.sed "s/\\\Wexpected_votes:.*/expected_votes:\ $num_hosts/g" $cs_conf
+ ssh -l root ${host} -- sed -i.sed "s/\\\Wtwo_node:.*/two_node:\ $two_node/g" $cs_conf
+ else
+ printf "%-10s Wrong quorum provider: installing $cs_conf for corosync instead\n" ${host}
+ create_cs_config
+ fi
+}
+
+function create_cs_config() {
+ cs_tmp=/tmp/cs_conf.$$
+ test $num_hosts != 2
+ two_node=$?
+
+ # Base config
+ priority="info"
+ if [ $do_debug = 1 ]; then
+ priority="debug"
+ fi
+
+ cat <<-END >$cs_tmp
+# Please read the corosync.conf.5 manual page
+totem {
+ version: 2
+
+ # cypto_cipher and crypto_hash: Used for mutual node authentication.
+ # If you choose to enable this, then do remember to create a shared
+ # secret with "corosync-keygen".
+ crypto_cipher: none
+ crypto_hash: none
+
+ # Assign a fixed node id
+ nodeid: $id
+
+ # Disable encryption
+ secauth: off
+
+ transport: $transport
+ inaddr_any: $inaddr_any
+
+ # interface: define at least one interface to communicate
+ # over. If you define more than one interface stanza, you must
+ # also set rrp_mode.
+ interface {
+ # Rings must be consecutively numbered, starting at 0.
+ ringnumber: 0
+
+ # This is normally the *network* address of the
+ # interface to bind to. This ensures that you can use
+ # identical instances of this configuration file
+ # across all your cluster nodes, without having to
+ # modify this option.
+ bindnetaddr: $ip
+
+ # However, if you have multiple physical network
+ # interfaces configured for the same subnet, then the
+ # network address alone is not sufficient to identify
+ # the interface Corosync should bind to. In that case,
+ # configure the *host* address of the interface
+ # instead:
+ # bindnetaddr: 192.168.1.1
+ # When selecting a multicast address, consider RFC
+ # 2365 (which, among other things, specifies that
+ # 239.255.x.x addresses are left to the discretion of
+ # the network administrator). Do not reuse multicast
+ # addresses across multiple Corosync clusters sharing
+ # the same network.
+
+ # Corosync uses the port you specify here for UDP
+ # messaging, and also the immediately preceding
+ # port. Thus if you set this to 5405, Corosync sends
+ # messages over UDP ports 5405 and 5404.
+ mcastport: $cs_port$dsh_group
+
+ # Time-to-live for cluster communication packets. The
+ # number of hops (routers) that this ring will allow
+ # itself to pass. Note that multicast routing must be
+ # specifically enabled on most network routers.
+ ttl: 1
+ mcastaddr: 226.94.1.1
+ }
+}
+
+logging {
+ debug: off
+ fileline: off
+ to_syslog: yes
+ to_stderr: no
+ syslog_facility: daemon
+ timestamp: on
+ to_logfile: yes
+ logfile: /var/log/corosync.log
+ logfile_priority: $priority
+}
+
+amf {
+ mode: disabled
+}
+
+quorum {
+ provider: corosync_votequorum
+ expected_votes: $num_hosts
+ votes: 1
+ two_node: $two_node
+ wait_for_all: 0
+ last_man_standing: 0
+ auto_tie_breaker: 0
+}
+END
+ scp -q $cs_tmp root@${host}:$cs_conf
+ rm -f $cs_tmp
+}
+
+for host in $host_list; do
+ echo ""
+ echo ""
+ echo "* Configuring $host"
+
+ cs_short_host=`name_for_node $host`
+ ip=`ip_for_node $host`
+ id=`id_for_node $host`
+
+ echo $ip | grep -qis NXDOMAIN
+ if [ $? = 0 ]; then
+ echo "Couldn't find resolve $host to an IP address"
+ exit 1
+ fi
+
+ if [ `uname -n` = $host ]; then
+ bash $init
+ else
+ cat $init | ssh -l root -T $host -- "cat > $init; bash $init"
+ fi
+
+ if [ "x$fence_conf" != x ]; then
+ if [ -e $fence_conf ]; then
+ scp $fence_conf root@${host}:$fence_conf
+ fi
+ fi
+
+ if [ $ETCHOSTS = 1 ]; then
+ scp /etc/hosts root@${host}:/etc/hosts
+ fi
+
+ ssh -l root ${host} -- grep -q "token:" $cs_conf 2>&1 > /dev/null
+ new_config=$?
+ new_config=1
+
+ if [ $new_config = 0 ]; then
+ printf "%-10s Updating $cs_conf\n" ${host}:
+ patch_cs_config
+ else
+ printf "%-10s Installing $cs_conf\n" ${host}:
+ create_cs_config
+ fi
+done