#!/bin/sh

# Disaster simplification script for Slony.  Allows easy command-line movement
# of slony origins, or failover if needed.  Extracts most of the needed information
# from the database itself.

# $Id: slony_switchover.sh 309 2008-05-12 17:51:26Z wmoran $

# Author: Bill Moran <wmoran@collaborativefusion.com>

# Copyright 2008 Collaborative Fusion Inc.

# This program is free software; you can redistribute it and/or modify
# it under the terms of the Q Public License.
# In laymans terms, you may distribute and use this software
# as you like as long as you maintain this copyright notice.  You may
# modify the software and distribute your modifications: by doing so
# you grant Collaborative Fusion the right to incorporate your
# modifications into the version of the software copyrighted by
# Collaborative Fusion.

# 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.

usage()
{
  echo 'usage: [-f] -d database [-c cluster] [-s set] [-t target master] [-U user]'
  echo '-f: force (FAILOVER instead of SWITCHOVER)'
  echo '-d: database name'
  echo '-c: Cluster name (defaults to database name)'
  echo '-s: Set (defaults to 1)'
  echo '-t: target (new origin) (defaults to this host)'
  echo '-U: user to connect to local DB as (defaults to slony)'
  exit 2
}

args=`getopt fd:c:s:t:U: $*`
if [ $? -ne 0 ]
then
  usage
fi
set -- $args
for i
do
  case "$i"
  in
    -f)
      FORCE=1;
      shift;;
    -d)
      DB=$2;
      shift; shift;;
    -c)
      CLUSTER=$2;
      shift; shift;;
    -s)
      SET=$2;
      shift; shift;;
    -t)
      TARGET=$2;
      shift; shift;;
    -U)
      PUSER=$2;
      shift; shift;;
    --)
      shift; break;;
  esac
done
if [ "x$DB" = "x" ]
then
  usage
fi
if [ "x$CLUSTER" = "x" ]
then
  CLUSTER=$DB
fi
if [ "x$SET" = "x" ]
then
  SET=1
fi
if [ "x$PUSER" = "x" ]
then
  PUSER=slony
fi

PSQL=`which psql`
select_sql()
{
  R=`$PSQL -R " " -t -U $PUSER -d $DB -A -c "$1" | /usr/bin/tail -1`
  echo $R
}

ME=`select_sql "SELECT last_value FROM _$CLUSTER.sl_local_node_id"`
if [ "x$TARGET" = "x" ]
then
  TARGET=$ME
fi
PREAMBLE="cluster name = $CLUSTER;"

for I in `select_sql "SELECT no_id FROM _$CLUSTER.sl_node"`;
do
  if [ $ME -eq $I ]
  then
    PREAMBLE="$PREAMBLE node $I admin conninfo='dbname=$DB host=/tmp user=$PUSER';"
  else
    NODE=`select_sql "SELECT pa_conninfo FROM _$CLUSTER.sl_path WHERE pa_client=$ME AND pa_server=$I"`
    if [ "x$NODE" = "x" ]
    then
      echo "Fatal!: no conninfo found for node $I" 
      exit 1;
    fi
    PREAMBLE="$PREAMBLE node $I admin conninfo='$NODE';"
  fi
done

ORIGIN=`select_sql "SELECT set_origin FROM _$CLUSTER.sl_set WHERE set_id=$SET"`

ACTION="
lock set (id=$SET, origin=$ORIGIN);
wait for event (origin=$ORIGIN, confirmed=$TARGET);
move set (id=$SET, old origin=$ORIGIN, new origin=$TARGET);
wait for event (origin=$ORIGIN, confirmed=$TARGET);
"

if [ "x$FORCE" = "x1" ]
then
  ACTION="failover (id=$SET, backup node=$TARGET);"
fi

echo "$PREAMBLE $ACTION" | slonik

