]> granicus.if.org Git - ejabberd/commitdiff
add mnesia cluster helper scripts
authorChristophe Romain <christophe.romain@process-one.net>
Fri, 6 Mar 2015 14:40:09 +0000 (15:40 +0100)
committerChristophe Romain <christophe.romain@process-one.net>
Fri, 6 Mar 2015 14:42:41 +0000 (15:42 +0100)
Makefile.in
ejabberdctl.template
tools/joincluster [new file with mode: 0755]
tools/leavecluster [new file with mode: 0755]

index 27d55dad61b2c972c6b9fc899f10c0f3e828dad9..68e3b06b82e66addd9673008fc0b01c61dc50cfa 100644 (file)
@@ -167,6 +167,8 @@ install: all
        # Binary C programs
        $(INSTALL) -d $(PBINDIR)
        $(INSTALL) -m 750 $(O_USER) tools/captcha.sh $(PBINDIR)
+       $(INSTALL) -m 750 $(O_USER) tools/joincluster $(PBINDIR)
+       $(INSTALL) -m 750 $(O_USER) tools/leavecluster $(PBINDIR)
        -[ -f deps/p1_pam/priv/bin/epam ] \
                && $(INSTALL) -m 750 $(O_USER) deps/p1_pam/priv/bin/epam $(PBINDIR)
        #
index 2025fd22d8ffb8f2a7e0d17516eaae2d43368cd5..eccaca26ed6300e3065c476bbd1b817a31bf0dcf 100755 (executable)
@@ -428,6 +428,16 @@ check_start()
     }
 }
 
+# cluster setup
+join_cluster()
+{
+    $EJABBERD_BIN_PATH/joincluster $*
+}
+leave_cluster()
+{
+    $EJABBERD_BIN_PATH/leavecluster $*
+}
+
 # allow sync calls
 wait_for_status()
 {
@@ -458,5 +468,7 @@ case $ARGS in
     ' etop') etop;;
     ' started') wait_for_status 0 30 2;; # wait 30x2s before timeout
     ' stopped') wait_for_status 3 15 2 && stop_epmd;; # wait 15x2s before timeout
+    ' join_cluster '*) join_cluster ${ARGS/ join_cluster /};;
+    ' leave_cluster '*) leave_cluster ${ARGS/ leave_cluster /};;
     *) ctl $ARGS;;
 esac
diff --git a/tools/joincluster b/tools/joincluster
new file mode 100755 (executable)
index 0000000..e4351d7
--- /dev/null
@@ -0,0 +1,152 @@
+#!/bin/bash
+
+# Add the current ejabberd node in a cluster
+
+# copyright (c) 2010-2015 ProcessOne
+#
+# This script is proprietary software and cannot be published or redistribute.
+
+# Return Code:
+#  0 : groovy baby
+# 11 : erl not found
+# 12 : erlc not found
+# 20 : database dir doesn't exist
+# 21 : database dir not writable
+# 21 : database dir variable not set
+# 30 : network issue
+# 31 : node names incompatibility
+
+function error
+{
+    echo "Error: $1" >&2
+    exit $2
+}
+
+echo "--------------------------------------------------------------------"
+echo ""
+echo "ejabberd cluster configuration"
+echo ""
+echo "This ejabberd node will be configured for use in an ejabberd cluster."
+echo "IMPORTANT: all local data from the database will be lost, and"
+echo "cluster database will be initialized. All data from the master"
+echo "node will be replicated to this one."
+echo ""
+echo "--------------------------------------------------------------------"
+echo "Press any key to continue, or Ctrl+C to stop now"
+read foo
+echo ""
+
+[ $# -eq 0 ] && {
+    echo "Make sure you have a running remote master ejabberd node"
+    echo "Before continuing, you must copy the ~/.erlang.cookie file from"
+    echo "remote master node and check ejabberd.cfg compatibility."
+    echo "e.g. hosts definition must match on all nodes"
+    echo ""
+    echo "The remote master node name is defined as ERLANG_NODE into"
+    echo "ejabberdctl.cfg on that remote node."
+    echo ""
+    echo -n "Remote master node name: "
+    read REMOTE
+    echo ""
+} || {
+    echo "Using passed parameter for remote master node name: $1"
+    REMOTE=$1
+}
+
+cont=Y
+ping -q -c 1 ${REMOTE#*@} 2>/dev/null >/dev/null
+[ $? -eq 0 ] || {
+    echo "Cannot ping ${REMOTE#*@}. Are you sure network setup is correct ?"
+    echo -n "Should we continue anyway ? (Y/n) "
+    read cont
+}
+cont=`echo $cont | tr a-z A-Z`
+[ "$cont" == "Y" ] || error "Check your network configuration (dns, firewall, etc...)" 30
+
+HERE=`which "$0"`
+BASE=`dirname $HERE`/..
+ROOTDIR=`cd $BASE; pwd`
+. $ROOTDIR/bin/ejabberdctl stop 2>/dev/null >/dev/null
+NAME=-name
+[ "$ERLANG_NODE" = "${ERLANG_NODE%.*}" ] && NAME=-sname
+PA=/tmp/clustersetup_$$
+CLUSTERSETUP=clustersetup
+CLUSTERSETUP_ERL=$PA/$CLUSTERSETUP.erl
+
+REMOTENAME=-name
+[ "$REMOTE" = "${REMOTE%.*}" ] && REMOTENAME=-sname
+[ "$REMOTENAME" = "$NAME" ] || {
+    echo "IMPORTANT!: node names are incompatible"
+    echo "Remote node name is $REMOTE"
+    echo "Local node name is $ERLANG_NODE"
+    echo ""
+    echo "Both node names must be short or fqdn names."
+    echo "Using short and fqdn names is impossible."
+    echo ""
+    error "incompatible node names" 31
+}
+
+set -o errexit
+set -o nounset
+
+echo "Using commands:"
+which erl  || error "can't find erl"  11
+which erlc || error "can't find erlc" 12
+echo ""
+
+[ -d $SPOOL_DIR ] && rm -Rf $SPOOL_DIR
+mkdir $SPOOL_DIR || error "$SPOOL_DIR cannot be created" 20
+[ -w $SPOOL_DIR ] || error "$SPOOL_DIR directory is not writable" 21
+
+cd $ROOTDIR
+mkdir -p $PA
+cat <<EOF > $CLUSTERSETUP_ERL
+-module($CLUSTERSETUP).
+
+-export([start/0]).
+
+set_table_copy(Table, _Node, {badrpc, Reason}) ->
+    io:format("Error: cannot get storage type for table ~p on node $REMOTE:~n ~p~n",[Table, Reason]);
+set_table_copy(Table, Node, Type) ->
+    io:format("setting table ~p to mode ~p~n",[Table, Type]),
+    case mnesia:add_table_copy(Table, Node, Type) of
+    {aborted, _} ->
+        mnesia:change_table_copy_type(Table, Node, Type);
+    _ ->
+        ok
+    end.
+
+set_tables({badrpc, Reason}) ->
+    io:format("ERROR: cannot get tables list on $REMOTE : ~p~n",[Reason]);
+set_tables([]) ->
+    ok;
+set_tables([schema | Tables]) ->
+    set_tables(Tables);
+set_tables([s2s | Tables]) ->
+    set_tables(Tables);
+set_tables([session | Tables]) ->
+    set_tables(Tables);
+set_tables([Table | Tables]) ->
+    set_table_copy(Table, node(),
+                   rpc:call('$REMOTE', mnesia, table_info, [Table, storage_type])),
+    set_tables(Tables).
+
+start() ->
+    io:format("~n",[]),
+    R = case net_adm:ping('$REMOTE') of
+        pong ->
+            set_table_copy(schema, node(), disc_copies),
+            set_tables(rpc:call('$REMOTE', mnesia, system_info, [tables])),
+            0;
+        pang ->
+            io:format("node ~p is not reachable, please check epmd port, and FIREWALL_WINDOW ports~n", ['$REMOTE']),
+            1
+    end,
+    halt(R).
+EOF
+erlc -o $PA $CLUSTERSETUP_ERL
+sh -c "erl $NAME $ERLANG_NODE -pa $PA $KERNEL_OPTS -mnesia extra_db_nodes \"['$REMOTE']\" dir \"\\\"$SPOOL_DIR\\\"\" -s mnesia -s $CLUSTERSETUP start"
+rm -Rf $PA
+
+echo "End."
+echo "Check that there is no error in the above messages."
diff --git a/tools/leavecluster b/tools/leavecluster
new file mode 100755 (executable)
index 0000000..ec21621
--- /dev/null
@@ -0,0 +1,97 @@
+#!/bin/bash
+
+# Remove the current ejabberd node in a cluster
+
+# copyright (c) 2010-2015 ProcessOne
+#
+# This script is proprietary software and cannot be published or redistribute.
+
+# Return Code:
+#  0 : groovy baby
+# 11 : erl not found
+# 12 : erlc not found
+# 20 : database dir doesn't exist
+# 21 : database dir not writable
+# 21 : database dir variable not set
+
+function error
+{
+    echo "Error: $1" >&2
+    exit $2
+}
+
+echo "--------------------------------------------------------------------"
+echo ""
+echo "ejabberd cluster configuration"
+echo ""
+echo "This ejabberd node will be removed from the cluster."
+echo "IMPORTANT: this node will be stopped. At least one other clustered"
+echo "node must be running."
+echo ""
+echo "--------------------------------------------------------------------"
+echo "Press any key to continue, or Ctrl+C to stop now"
+read foo
+echo ""
+
+HERE=`which "$0"`
+BASE=`dirname $HERE`/..
+ROOTDIR=`cd $BASE; pwd`
+. $ROOTDIR/bin/ejabberdctl stop 2>/dev/null >/dev/null
+$ROOTDIR/bin/ejabberdctl stopped
+PA=/tmp/clustersetup_$$
+CLUSTERSETUP=clustersetup
+CLUSTERSETUP_ERL=$PA/$CLUSTERSETUP.erl
+
+set -o errexit
+set -o nounset
+
+echo "Using commands:"
+which erl  || error "can't find erl"  11
+which erlc || error "can't find erlc" 12
+echo ""
+
+cd $ROOTDIR
+mkdir -p $PA
+cat <<EOF > $CLUSTERSETUP_ERL
+-module($CLUSTERSETUP).
+
+-export([start/0]).
+
+del_table_copy(Table, Node) ->
+    case mnesia:del_table_copy(Table, Node) of
+    {aborted, Reason} -> io:format("Error: can not remove ~p table: ~p~n", [Table, Reason]);
+    _ -> io:format("table ~p removed from cluster~n", [Table])
+    end.
+
+del_tables([],_) ->
+    ok;
+del_tables([schema | Tables], Node) ->
+    del_tables(Tables, Node);
+del_tables([Table | Tables], Node) ->
+    del_table_copy(Table, Node),
+    del_tables(Tables, Node).
+
+start() ->
+    io:format("~n",[]),
+    Removed = node(),
+    case mnesia:system_info(running_db_nodes)--[Removed] of
+    [] -> io:format("Error: no other node running in the cluster~n");
+    Nodes ->
+        del_tables(mnesia:system_info(local_tables), Removed),
+        mnesia:stop(),
+        case rpc:call(hd(Nodes), mnesia, del_table_copy, [schema, Removed]) of
+        {badrpc,Reason} -> io:format("Error: can not unregister node ~p from cluster: ~p~n", [Removed, Reason]);
+        {aborted,Reason} -> io:format("Error: can not unregister node ~p from cluster: ~p~n", [Removed, Reason]);
+        {atomic, ok} ->
+            mnesia:delete_schema([Removed]),
+            io:format("node ~p removed from cluster~n", [Removed])
+        end
+    end,
+    halt(0).
+EOF
+erlc -o $PA $CLUSTERSETUP_ERL
+sh -c "erl $NAME $ERLANG_NODE -pa $PA $KERNEL_OPTS -mnesia dir "\"$SPOOL_DIR\"" -s mnesia -s $CLUSTERSETUP start"
+rm -Rf $PA
+
+echo "End."
+echo "Check that there is no error in the above messages."