Sun Jul 25 04:03:01 PDT 2004
- Previous message: [Slony1-commit] By cbbrowne: New Directory
- Next message: [Slony1-commit] By darcyb: Work around braindead m4 processors on some OS's also to be
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Log Message:
-----------
Add in a "first draft" of a set of Perl tools for configuring Slony-I
instances that work by generating Slonik scripts.
They do not use any specialized PostgreSQL modules, so as to maximize
the chance that they will run portably even on commercial Un*xes where
it may be impractical to add things like Pg or DBD:PG.
Added Files:
-----------
slony1-engine/tools/altperl:
README (r1.1)
ToDo (r1.1)
create_set.pl (r1.1)
drop_node.pl (r1.1)
drop_set.pl (r1.1)
failover.pl (r1.1)
init_cluster.pl (r1.1)
merge_sets.pl (r1.1)
move_set.pl (r1.1)
reset_cluster.pl (r1.1)
restart_node.pl (r1.1)
slon-tools.pm (r1.1)
slon.env (r1.1)
slon_kill.pl (r1.1)
slon_pushsql.pl (r1.1)
slon_start.pl (r1.1)
slon_watchdog.pl (r1.1)
subscribe_set.pl (r1.1)
uninstall_node.pl (r1.1)
unsubscribe_set.pl (r1.1)
update_node.pl (r1.1)
-------------- next part --------------
--- /dev/null
+++ tools/altperl/merge_sets.pl
@@ -0,0 +1,47 @@
+#!/usr/bin/perl
+# $Id: merge_sets.pl,v 1.1 2004/07/25 04:02:50 cbbrowne Exp $
+# Author: Christopher Browne
+# Copyright 2004 Afilias Canada
+
+require 'slon-tools.pm';
+require 'slon.env';
+
+my ($node, $set1, $set2) = @ARGV;
+if ($node =~ /^node(\d+)$/) {
+ # Set name is in proper form
+ $node = $1;
+} else {
+ print "Valid node names are node1, node2, ...\n\n";
+ die "Usage: ./merge_sets.pl nodeN setOLD setNEW\n";
+}
+
+if ($set1 =~ /^node(\d+)$/) {
+ $set1 = $1;
+} else {
+ print "Valid set names are set1, set2, ...\n\n";
+ die "Usage: ./merge_sets.pl nodeN setOLD setNEW\n";
+}
+if ($set2 =~ /^node(\d+)$/) {
+ $set2 = $1;
+} else {
+ print "Valid set names are set1, set2, ...\n\n";
+ die "Usage: ./merge_sets.pl nodeN setOLD setNEW\n";
+}
+
+open(SLONIK, ">/tmp/slonik.$$");
+print SLONIK genheader();
+my ($dbname, $dbhost)=($DBNAME[1], $HOST[1]);
+print SLONIK qq[
+ try {
+ merge set (id = $set1, add id = $set2, origin = $node);
+ }
+ on error {
+ echo 'Failure to merge sets $set1 and $set2 with origin $node';
+ exit 1;
+ }
+ echo 'Replication set $set2 merged in with $set1 on origin $node';
+];
+
+close SLONIK;
+`slonik < /tmp/slonik.$$`;
+unlink("/tmp/slonik.$$");
--- /dev/null
+++ tools/altperl/create_set.pl
@@ -0,0 +1,111 @@
+#!/usr/bin/perl
+# $Id: create_set.pl,v 1.1 2004/07/25 04:02:50 cbbrowne Exp $
+# Author: Christopher Browne
+# Copyright 2004 Afilias Canada
+require 'slon-tools.pm';
+require 'slon.env';
+my ($set) = @ARGV;
+if ($set =~ /^set(\d+)$/) {
+ $set = $1;
+} else {
+ print "Need set identifier\n";
+ die "create_set.pl setN\n";
+}
+
+$OUTPUTFILE="/tmp/add_tables.$$";
+
+open (OUTFILE, ">$OUTPUTFILE");
+print OUTFILE genheader();
+
+foreach my $table (@SERIALTABLES) {
+ print OUTFILE "
+ echo ' Adding unique key to table public.$table...';
+ table add key (
+ node id=1,
+ full qualified name='public.$table'
+ );
+";
+}
+close OUTFILE;
+print `slonik < $OUTPUTFILE`;
+
+open (OUTFILE, ">$OUTPUTFILE");
+print OUTFILE genheader();
+
+print OUTFILE "
+ try {
+ create set (id = $set, origin = 1, comment = 'Set for slony tables');
+ }
+ on error {
+ echo 'Could not create subscription set!';
+ exit -1;
+ }
+";
+
+close OUTFILE;
+print `slonik < $OUTPUTFILE`;
+
+open (OUTFILE, ">$OUTPUTFILE");
+print OUTFILE genheader();
+print OUTFILE "
+ echo 'Subscription set created';
+ echo 'Adding tables to the subscription set';
+
+";
+
+$TABLE_ID=1;
+foreach my $table (@SERIALTABLES) {
+ if ($table =~ /^(.*\..*)$/) {
+ # Table has a namespace specified
+ } else {
+ $table = "public.$table";
+ }
+ print OUTFILE "
+ set add table (set id = $set, origin = 1, id = $TABLE_ID, full qualified name = '$table', comment = 'Table public.$table', key=serial);
+ echo 'Add unkeyed table $table';
+";
+ $TABLE_ID++;
+}
+
+foreach my $table (@KEYEDTABLES) {
+ if ($table =~ /^(.*\..*)$/) {
+ # Table has a namespace specified
+ } else {
+ $table = "public.$table";
+ }
+ print OUTFILE "
+ set add table (set id = $set, origin = 1, id = $TABLE_ID, full qualified name = '$table', comment = 'Table public.$table');
+ echo 'Add keyed table $table';
+";
+ $TABLE_ID++;
+}
+
+close OUTFILE;
+print `slonik < $OUTPUTFILE`;
+
+open (OUTFILE, ">$OUTPUTFILE");
+print OUTFILE genheader();
+# Finish subscription set...
+print OUTFILE "
+ echo 'Adding sequences to the subscription set';
+";
+
+$SEQID=1;
+foreach my $seq (@SEQUENCES) {
+ if ($seq =~ /^(.*\..*)$/) {
+ # Table has a namespace specified
+ } else {
+ $seq = "public.$seq";
+ }
+ print OUTFILE "
+ set add sequence (set id = $set, origin = 1, id = $SEQID, full qualified name = '$seq', comment = 'Sequence public.$seq');
+ echo 'Add sequence $seq';
+";
+ $SEQID++;
+}
+print OUTFILE "
+ echo 'All tables added';
+";
+
+print `slonik < $OUTPUTFILE`;
+unlink($OUTPUTFILE);
--- /dev/null
+++ tools/altperl/subscribe_set.pl
@@ -0,0 +1,53 @@
+#!/usr/bin/perl
+# $Id: subscribe_set.pl,v 1.1 2004/07/25 04:02:51 cbbrowne Exp $
+# Author: Christopher Browne
+# Copyright 2004 Afilias Canada
+
+require 'slon-tools.pm';
+require 'slon.env';
+my ($set, $node) = @ARGV;
+if ($node =~ /^node(\d+)$/) {
+ $node = $1;
+} else {
+ print "Need to specify node!\n";
+ die "subscribe_set setM nodeN\n";
+}
+
+if ($set =~ /^set(\d+)$/) {
+ $set = $1;
+} else {
+ print "Need to specify set!\n";
+ die "subscribe_set setM nodeN\n";
+}
+
+open(SLONIK, ">/tmp/slonik-subscribe.$$");
+print SLONIK genheader();
+print SLONIK "try {\n";
+
+if ($DSN[$node]) {
+ my $parent = 1;
+ my $forward;
+ if ($PARENT[$node]) {
+ $parent = $PARENT[$node];
+ }
+ if ($NOFORWARD[$node] eq "no") {
+ $forward = "no";
+ } else {
+ $forward = "yes";
+ }
+ print SLONIK " subscribe set (id = $set, provider = $parent, receiver = $node, forward = $forward);\n";
+} else {
+ die "Node $node not found\n";
+}
+
+print SLONIK "}\n";
+print SLONIK qq{
+ on error {
+ exit 1;
+ }
+ echo 'Subscribed nodes to set 1';
+};
+
+close SLONIK;
+print `slonik < /tmp/slonik-subscribe.$$`;
+unlink("/tmp/slonik-subscribe.$$");
--- /dev/null
+++ tools/altperl/init_cluster.pl
@@ -0,0 +1,206 @@
+#!/usr/bin/perl
+# $Id: init_cluster.pl,v 1.1 2004/07/25 04:02:50 cbbrowne Exp $
+# Author: Christopher Browne
+# Copyright 2004 Afilias Canada
+my @COST;
+my @PATH;
+
+require 'slon-tools.pm';
+require 'slon.env';
+my $FILE="init-cluster";
+open(SLONIK, ">/tmp/$FILE.$$");
+
+print SLONIK genheader();
+
+my ($dbname, $dbhost)=($DBNAME[1], $HOST[1]);
+print SLONIK "
+try {
+ init cluster (id = 1, comment = 'Node $dbname@$dbhost');
+";
+
+foreach my $node (@NODES) {
+ if ($node > 1) { # skip the first one; it's already initialized!
+ my ($dbname, $dbhost) = ($DBNAME[$node], $HOST[$node]);
+ print SLONIK " store node (id = $node, comment = 'Node $dbname@$dbhost');\n";
+ }
+}
+
+print SLONIK "} on error {
+ echo 'Could not set up all nodes as slonik nodes';
+ exit 1;
+}
+echo 'Set up replication nodes';
+";
+close SLONIK;
+
+`slonik < /tmp/$FILE.$$`;
+
+open(SLONIK, ">/tmp/$FILE.$$");
+print SLONIK genheader();
+
+my @VIA ;
+generate_listen_paths();
+report_on_paths();
+print SLONIK qq[
+echo 'Next: configure paths for each node/origin';
+];
+foreach my $nodea (@NODES) {
+ my $dsna = $DSN[$nodea];
+ foreach my $nodeb (@NODES) {
+ if ($nodea != $nodeb) {
+ my $dsnb = $DSN[$nodeb];
+ my $providerba = $VIA[$nodea][$nodeb];
+ my $providerab = $VIA[$nodeb][$nodea];
+ print SLONIK " store path (server = $nodea, client = $nodeb, conninfo = '$dsna');\n";
+ print SLONIK " store path (server = $nodeb, client = $nodea, conninfo = '$dsnb');\n";
+ print SLONIK "echo 'configured path between $nodea and $nodeb';\n";
+ }
+ }
+}
+
+close SLONIK;
+
+`slonik < /tmp/$FILE.$$`;
+
+open(SLONIK, ">/tmp/$FILE.$$");
+print SLONIK genheader();
+
+foreach my $origin (@NODES) {
+ my $dsna = $DSN[$origin];
+ foreach my $receiver (@NODES) {
+ if ($origin != $receiver) {
+ my $provider = $VIA[$origin][$receiver];
+ print SLONIK " store listen (origin = $origin, receiver = $receiver, provider = $provider);\n";
+ }
+ }
+}
+
+print SLONIK qq[
+ echo 'Replication nodes prepared';
+ echo 'Please start the replication daemon on both systems';
+];
+
+close SLONIK;
+`slonik < /tmp/$FILE.$$`;
+unlink("/tmp/$FILE.$$");
+
+sub generate_listen_paths {
+ my @COST;
+ my @PATH;
+
+ my $infinity = 10000000; # Initial costs are all infinite
+ foreach my $node1 (@NODES) {
+ foreach my $node2 (@NODES) {
+ $COST[$node1][$node2] = $infinity;
+ }
+ }
+
+ # Initialize paths between parents and children, and based on them,
+ # generate initial seeding of listener paths, @VIA
+
+ foreach my $node1 (@NODES) {
+ $COST[$node1][$node1] = 0;
+ $VIA[$node1][$node1] = 0;
+ foreach my $node2 (@NODES) {
+ if ($node2 != $node1) {
+ if ($PARENT[$node1] == $node2) {
+ $PATH[$node1][$node2] = 1;
+ $PATH[$node2][$node1] = 1;
+ # Set up a cost 1 path between them
+ # Parent to child
+ $COST[$node1][$node2] = 1;
+ $VIA[$node1][$node2] = $node1;
+
+ # Child to parent
+ $COST[$node2][$node1] = 1;
+ $VIA[$node2][$node1] = $node2;
+ }
+ }
+ }
+ }
+
+ # Now, update the listener paths...
+ # 4 level nested iteration:
+ # 1 while not done, do
+ # 2 for each node, node1
+ # 3 for each node, node2, where node2 <> node1, where we don't
+ # yet have a listener path
+ # 4 for each node node3 (<> node1 or node2),
+ # consider introducing the listener path:
+ # node1 to node2 then node2 to node3
+ # In concept, it's an O(n^4) algorithm; since the number of nodes, n,
+ # is not likely to get particularly large, it's not worth tuning
+ # further.
+ $didwork = "yes";
+ while ($didwork eq "yes") {
+ $didwork = "no";
+ foreach my $node1 (@NODES) {
+ foreach my $node3 (@NODES) {
+ if (($VIA[$node3][$node1] == 0) && ($node3 != $node1)) {
+ foreach my $node2 (@NODES) {
+ if ($PATH[$node1][$node2] && ($VIA[$node2][$node3] != 0) && ($node2 != $node3) && ($node2 != $node1)) {
+ # Consider introducing a path from n1 to n2 then n2 to n3
+ # as a cheaper alternative to going direct from n1 to n3
+ my $oldcost = $COST[$node3][$node1];
+ my $newcost = $COST[$node1][$node2] + $COST[$node2][$node3];
+ if ($newcost < $oldcost) {
+ $didwork = "yes";
+ # So we go via node 2
+ $VIA[$node3][$node1] = $node2;
+ $COST[$node3][$node1] = $newcost;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+sub report_on_paths {
+ print "cost\n";
+ print " ";
+ foreach my $node2 (@NODES) {
+ printf "%4d|", $node2;
+ }
+ print "\n--------------------------------------------\n";
+ foreach my $node1 (@NODES) {
+ printf "%4d|", $node1;
+ foreach my $node2 (@NODES) {
+ if ($COST[$node2][$node1] == $infinity) {
+ printf "inf ";
+ } else {
+ printf "%4d ", $COST[$node2][$node1];
+ }
+ print "\n";
+ }
+ }
+ print "\n\n";
+ print "VIA\n";
+ print " ";
+ foreach my $node2 (@NODES) {
+ printf "%4d|", $node2;
+ }
+ print "\n--------------------------------------------\n";
+ foreach my $node1 (@NODES) {
+ printf "%4d", $node1;
+ foreach my $node2 (@NODES) {
+ printf "%4d ", $VIA[$node2][$node1];
+ }
+ print "\n";
+ }
+
+ print "PATHS\n";
+ print " ";
+ foreach my $node2 (@NODES) {
+ printf "%4d|", $node2;
+ }
+ print "\n--------------------------------------------\n";
+ foreach my $node1 (@NODES) {
+ printf "%4d", $node1;
+ foreach my $node2 (@NODES) {
+ printf "%4d ", $PATH[$node2][$node1];
+ }
+ print "\n";
+ }
+}
--- /dev/null
+++ tools/altperl/slon.env
@@ -0,0 +1,126 @@
+# $Id: slon.env,v 1.1 2004/07/25 04:02:50 cbbrowne Exp $
+# Author: Christopher Browne
+# Copyright 2004 Afilias Canada
+
+$SETNAME=flex2test;
+$LOGDIR='/opt/logs/slon';
+$SLON_BIN_PATH='/opt/OXRS/dbs/pgsql74/bin';
+
+add_node(host => 'marge', dbname=>'transtest', port=>5532,
+ user=>'postgres', password=>'postgres', node=>1);
+
+add_node(host => 'marge', dbname=>'transreplica', port=>5533,
+ user=>'postgres', password=>'postgres', node=>2, parent=>1);
+
+add_node(host => 'marge', dbname=>'transreplica', port=>5534, user=>'postgres',
+ password=>'postgres', node=>3, parent=>1);
+
+# add_node(host => 'marge', dbname=>'flexnodeb', port=>5532,user=>'postgres',
+# password=>'postgres', node=>4, parent=>3);
+
+# add_node(host => 'marge', dbname=>'flexnodec', port=>5532,user=>'postgres',
+# password=>'postgres', node=>5, parent=>4);
+
+# add_node(host => 'marge', dbname=>'flexnoded', port=>5532,user=>'postgres',
+# password=>'postgres', node=>6, parent=>3);
+# add_node(host => 'marge', dbname=>'flexnodee', port=>5532,user=>'postgres',
+# password=>'postgres', node=>7, parent=>6, noforward=>'no');
+
+# These are the tables that already have unique keys, that therefore do
+# not need for Slony-I to add sequences/indices
+ at KEYEDTABLES=(
+ "balance_history",
+ "billing_account",
+ "bl_update_reason",
+ "epp_activity",
+ "epp_contact",
+ "epp_contact_map",
+ "epp_contact_status",
+ "epp_dns_update",
+ "epp_domain",
+ "epp_domain_contact",
+ "epp_domain_host",
+ "epp_domain_protocol",
+ "epp_domain_protocol_history",
+ "epp_domain_status",
+ "epp_domain_trn_contact",
+ "epp_domain_trn_registrant",
+ "epp_host",
+ "epp_host_ip",
+ "epp_host_status",
+ "epp_poll_queue",
+ "epp_registrar",
+ "epp_registrar_contact",
+ "epp_registrar_notification",
+ "epp_registrar_role",
+ "epp_registrar_status",
+ "epp_registrar_tld",
+ "epp_registrar_zone",
+ "epp_role",
+ "epp_server",
+ "epp_trans_log",
+ "epp_trans_reason",
+ "epp_user",
+ "fee_schedule",
+ "flex_tld",
+ "flex_zone",
+ "idn_script"
+ );
+
+# Here are the tables to be replicated that do NOT have unique
+# keys, to which Slony-I will have to add a key field
+ at SERIALTABLES=(
+ "epp_registrar_ipallow",
+ "epp_domain_renew",
+ "billing_event_logger",
+ "epp_registrar_low_threshold",
+ "epp_domain_archive",
+ "bl_update_history",
+ "res_country",
+ "billing_price",
+ "epp_log_1",
+ "epp_log_2",
+ "epp_log_3",
+ "epp_log_4",
+ "epp_log_5",
+ "epp_log_6",
+ "epp_log_7",
+ "epp_log_8",
+ "epp_log_9",
+ "billing_transaction_posted",
+ "billing_balance_history"
+ );
+
+# These are the applications' sequences that are to be
+# replicated
+ at SEQUENCES=(
+ "reserved_names_seq",
+ "epp_log_seq_",
+ "whois_cachemgmt_seq",
+ "flex_tld_id_seq",
+ "domain_seq",
+ "billing_seq",
+ "domain_lock_id_seq",
+ "bl_update_reason_id_seq",
+ "epp_log_active_seq",
+ "domain_id_seq",
+ "registrar_notification_id_seq",
+ "poll_id_seq",
+ "host_id_seq",
+ "fee_schedule_seq",
+ "registrar_id_seq",
+ "contact_id_seq",
+ "afilias_billable_trns_seq",
+ "trid_seq",
+ "role_id_seq",
+ "rpt_registrar_stats_id_seq",
+ "whois_activity_seq",
+ "epp_trans_log_id_seq",
+ "epp_activity_seq",
+ "bl_update_history_id_seq",
+ "whois_cachemgmt_server_seq",
+ "rrp_trid_seq",
+ "user_id_seq",
+ "dns_update_id_seq"
+ );
+
--- /dev/null
+++ tools/altperl/drop_set.pl
@@ -0,0 +1,28 @@
+#!/usr/bin/perl
+# $Id: drop_set.pl,v 1.1 2004/07/25 04:02:50 cbbrowne Exp $
+# Author: Christopher Browne
+# Copyright 2004 Afilias Canada
+
+require 'slon-tools.pm';
+require 'slon.env';
+my ($set) = @ARGV;
+if ($set =~ /^set(\d+)$/) {
+ $set = $1;
+} else {
+ print "Need set identifier\n";
+ croak "drop_set.pl setN\n";
+}
+
+open(SLONIK, "|slonik");
+
+print SLONIK genheader();
+
+print SLONIK qq{
+ try {
+ drop set (id = $set, origin=1);
+ }
+ on error {
+ exit 1;
+ }
+ echo 'Dropped set $set';
+};
--- /dev/null
+++ tools/altperl/slon_start.pl
@@ -0,0 +1,55 @@
+#!/usr/bin/perl
+# $Id: slon_start.pl,v 1.1 2004/07/25 04:02:50 cbbrowne Exp $
+# Author: Christopher Browne
+# Copyright 2004 Afilias Canada
+
+#start the slon daemon
+require 'slon-tools.pm';
+require 'slon.env';
+
+$node =$ARGV[0];
+
+if ( scalar(@ARGV) < 1 ) {
+ die "Usage: ./slon_start [node]\n";
+}
+
+if ($node =~ /^node\d+$/) {
+ # Node name is in proper form
+} else {
+ print "Valid node names are node1, node2, ...\n\n";
+ die "Usage: ./slon_start [node]\n";
+}
+
+get_pid();
+
+if ($pid) {
+ die "Slon is already running for set $SETNAME!\n";
+}
+
+$node =~ /node(\d*)$/;
+$nodenum = $1;
+my $dsn = $DSN[$nodenum];
+my $dbname=$DBNAME[$nodenum];
+system "$SLON_BIN_PATH/slon $SETNAME -s 1000 -d2 '$dsn' 2>$LOGDIR/slon-$dbname-$node.err >$LOGDIR/slon-$dbname-$node.out &";
+
+get_pid();
+
+if (!($pid)){
+ print "Slon failed to start for set $SETNAME!\n";
+} else {
+ print "Slon successfully started for set $SETNAME\n";
+ print "PID [$pid]\n";
+}
+#start the watchdog process
+system " perl slon_watchdog.pl $node 30 &";
+
+sub get_pid {
+ $node =~ /node(\d*)$/;
+ my $nodenum = $1;
+ my ($dbname, $dbport) = ($DBNAME[$nodenum], $PORT[$nodenum]);
+# print "Searching for PID for $dbname on port $dbport\n";
+ open(PSOUT, "ps -auxww | egrep \"[s]lon $SETNAME\" | egrep \"dbname=$dbname .*port=$dbport\" | sort -n | awk '{print \$2}'|");
+ $pid = <PSOUT>;
+ chop $pid;
+ close(PSOUT);
+}
--- /dev/null
+++ tools/altperl/reset_cluster.pl
@@ -0,0 +1,50 @@
+#!/usr/bin/perl
+# $Id: reset_cluster.pl,v 1.1 2004/07/25 04:02:50 cbbrowne Exp $
+# Author: Christopher Browne
+# Copyright 2004 Afilias Canada
+
+require 'slon-tools.pm';
+require 'slon.env';
+
+open(SLONIK, ">/tmp/slonik.$$");
+
+print SLONIK genheader();
+
+my ($dbname, $dbhost)=($DBNAME[1], $HOST[1]);
+print SLONIK "
+ try {
+";
+
+foreach my $node (@NODES) {
+ if ($node > 1) {
+ my ($dbname, $dbhost) = ($DBNAME[$node], $HOST[$node]);
+ print SLONIK " store node (id = $node, comment = 'Node $dbname@$dbhost');\n";
+ }
+}
+
+foreach my $nodea (@NODES) {
+ my $dsna = $DSN[$nodea];
+ foreach my $nodeb (@NODES) {
+ if ($nodea != $nodeb) {
+ my $dsnb = $DSN[$nodeb];
+ print SLONIK " store path (server = $nodea, client = $nodeb, conninfo = '$dsna');\n";
+ print SLONIK " store path (server = $nodeb, client = $nodea, conninfo = '$dsnb');\n";
+ print SLONIK " store listen (origin = $nodea, receiver = $nodeb);\n";
+ print SLONIK " store listen (origin = $nodeb, receiver = $nodea);\n";
+ }
+ }
+}
+}
+print SLONIK qq[
+ }
+ on error {
+ exit 1;
+ }
+ echo 'Replication nodes prepared';
+ echo 'Please start the replication daemon on both systems';
+
+];
+
+close SLONIK;
+`slonik < /tmp/slonik.$$`;
+unlink("/tmp/slonik.$$");
--- /dev/null
+++ tools/altperl/unsubscribe_set.pl
@@ -0,0 +1,38 @@
+#!/usr/bin/perl
+# $Id: unsubscribe_set.pl,v 1.1 2004/07/25 04:02:51 cbbrowne Exp $
+# Author: Christopher Browne
+# Copyright 2004 Afilias Canada
+
+require 'slon-tools.pm';
+require 'slon.env';
+
+my ($set, $node) = @ARGV;
+if ($node =~ /^node(\d+)$/) {
+ $node = $1;
+} else {
+ print "Need to specify node!\n";
+ die "unsubscribe_set setM nodeN\n";
+}
+
+if ($set =~ /^set(\d+)$/) {
+ $set = $1;
+} else {
+ print "Need to specify set!\n";
+ die "unsubscribe_set setM nodeN\n";
+}
+
+open(SLONIK, ">/tmp/slonik-subscribe.$$");
+print SLONIK genheader();
+print SLONIK qq{
+ try {
+ unsubscribe set (id = $set, receiver = $node);
+ }
+ on error {
+ echo 'Failed to unsubscribe node $node from set $set';
+ exit 1;
+ }
+ echo 'unsubscribed node $node from set $set';
+};
+close SLONIK;
+print `slonik < /tmp/slonik-unsubscribe.$$`;
+unlink("/tmp/slonik-unsubscribe.$$");
--- /dev/null
+++ tools/altperl/restart_node.pl
@@ -0,0 +1,18 @@
+#!/usr/bin/perl
+# $Id: restart_node.pl,v 1.1 2004/07/25 04:02:50 cbbrowne Exp $
+# Author: Christopher Browne
+# Copyright 2004 Afilias Canada
+
+require 'slon-tools.pm';
+require 'slon.env';
+
+foreach my $node (@NODES) {
+ my $dsn = $DSN[$node];
+ open(SLONIK, "|slonik");
+ print SLONIK qq{
+ cluster name = $SETNAME ;
+ node $node admin conninfo = '$dsn';
+ restart node $node;
+ };
+ close SLONIK;
+}
--- /dev/null
+++ tools/altperl/failover.pl
@@ -0,0 +1,39 @@
+#!/usr/bin/perl
+# $Id: failover.pl,v 1.1 2004/07/25 04:02:50 cbbrowne Exp $
+# Author: Christopher Browne
+# Copyright 2004 Afilias Canada
+
+require 'slon-tools.pm';
+require 'slon.env';
+
+my ($node1, $node2) = @ARGV;
+if ($node1 =~ /^node(\d+)$/) {
+ $node1 = $1;
+} else {
+ print "Valid set names are set1, set2, ...\n\n";
+ die "Usage: ./failover.pl nodeN setOLD setNEW\n";
+}
+if ($node2 =~ /^node(\d+)$/) {
+ $node2 = $1;
+} else {
+ print "Valid set names are set1, set2, ...\n\n";
+ die "Usage: ./failover.pl nodeN setOLD setNEW\n";
+}
+
+open(SLONIK, ">/tmp/slonik.$$");
+print SLONIK genheader();
+my ($dbname, $dbhost)=($DBNAME[1], $HOST[1]);
+print SLONIK qq[
+ try {
+ failover (id = $node1, backup node = $node2);
+ }
+ on error {
+ echo 'Failure to fail node $node1 over to $node2';
+ exit 1;
+ }
+ echo 'Replication sets originating on $node1 failed over to $node2';
+];
+
+close SLONIK;
+`slonik < /tmp/slonik.$$`;
+unlink("/tmp/slonik.$$");
--- /dev/null
+++ tools/altperl/drop_node.pl
@@ -0,0 +1,31 @@
+#!/usr/bin/perl
+# $Id: drop_node.pl,v 1.1 2004/07/25 04:02:50 cbbrowne Exp $
+# Author: Christopher Browne
+# Copyright 2004 Afilias Canada
+
+require 'slon-tools.pm';
+require 'slon.env';
+
+my ($node) = @ARGV;
+if ($node =~ /^node(\d+)$/) {
+ $node = $1;
+} else {
+ print "Need to specify node!\n";
+ die "drop_node nodeN\n";
+}
+
+open(SLONIK, ">/tmp/slonik-drop.$$");
+print SLONIK genheader();
+print SLONIK qq{
+ try {
+ drop node (id = $node);
+ }
+ on error {
+ echo 'Failed to drop node $node from cluster';
+ exit 1;
+ }
+ echo 'dropped node $node cluster';
+};
+close SLONIK;
+print `slonik < /tmp/slonik-drop.$$`;
+unlink("/tmp/slonik-drop.$$");
--- /dev/null
+++ tools/altperl/slon-tools.pm
@@ -0,0 +1,73 @@
+#!/usr/bin/perl
+# $Id: slon-tools.pm,v 1.1 2004/07/25 04:02:50 cbbrowne Exp $
+# Author: Christopher Browne
+# Copyright 2004 Afilias Canada
+
+sub add_node {
+ my %PARAMS = (host=> undef,
+ dbname => 'template1',
+ port => 5432,
+ user => 'postgres',
+ node => undef,
+ password => undef,
+ parent => 1,
+ noforward => undef
+ );
+ my $K;
+ while ($K= shift) {
+ $PARAMS{$K} = shift;
+ }
+ die ("I need a node number") unless $PARAMS{'node'};
+ my $node = $PARAMS{'node'};
+ push @NODES, $node;
+ my $loginstr;
+ my $host = $PARAMS{'host'};
+ if ($host) {
+ $loginstr .= "host=$host";
+ $HOST[$node] = $host;
+ } else {
+ die("I need a host name") unless $PARAMS{'host'};
+ }
+ my $dbname = $PARAMS{'dbname'};
+ if ($dbname) {
+ $loginstr .= " dbname=$dbname";
+ $DBNAME[$node] = $dbname;
+ }
+ my $user=$PARAMS{'user'};
+ $loginstr .= " user=$user";
+ $USER[$node]= $user;
+
+ my $port = $PARAMS{'port'};
+ if ($port) {
+ $loginstr .= " port=$port";
+ $PORT[$node] = $port;
+ }
+ my $password = $PARAMS{'password'};
+ if ($password) {
+ $loginstr .= " password=$password";
+ $PASSWORD[$node] = $password;
+ }
+ $DSN[$node] = $loginstr;
+ my $parent = $PARAMS{'parent'};
+ if ($parent) {
+ $PARENT[$node] = $parent;
+ }
+ my $noforward = $PARAMS{'noforward'};
+ if ($noforward) {
+ $NOFORWARD[$node] = $noforward;
+ }
+}
+
+# This is the usual header to a slonik invocation that declares the
+# cluster name and the set of nodes and how to connect to them.
+sub genheader {
+ my $header = "cluster name = $SETNAME;\n";
+ foreach my $node (@NODES) {
+ if ($DSN[$node]) {
+ my $dsn = $DSN[$node];
+ $header .= " node $node admin conninfo='$dsn';\n";
+ }
+ }
+ return $header
+}
+return 1;
--- /dev/null
+++ tools/altperl/ToDo
@@ -0,0 +1,20 @@
+- Need to write a "repair_cluster.pl" script that
+ modifies configuration to reflect new configuration,
+ dropping and adding paths and listeners.
+
+ This would compare the configuration computed (as in init_cluster)
+ with the configuration actually found on some node, add "additional"
+ bits, and drop obsolete bits.
+
+- It would seem likely that the function "generate_listen_paths()" in
+ init_cluster.pl would be beneficial to port to pl/pgsql, as
+ there presently isn't any capability to rebuild the listener
+ paths by automatically dropping the old ones.
+
+- At present, the configuration generated by this set of tools is
+ fairly fragile. If just about any sort of error is made, it is
+ commonly needful to drop all of the Slony schemas, thereby cleaning
+ _everything_ out, and restarting the configuration process from
+ scratch.
+
+ That certainly isn't ideal.
--- /dev/null
+++ tools/altperl/update_node.pl
@@ -0,0 +1,17 @@
+#!/usr/bin/perl
+# $Id: update_node.pl,v 1.1 2004/07/25 04:02:51 cbbrowne Exp $
+# Author: Christopher Browne
+# Copyright 2004 Afilias Canada
+
+require 'slon-tools.pm';
+require 'slon.env';
+
+open(SLONIK, "|slonik");
+print SLONIK qq{
+ cluster name = $SETNAME ;
+ node 1 admin conninfo = '$CINFO1';
+ node 2 admin conninfo = '$CINFO2';
+
+ update functions (id = 1);
+ update functions (id = 2);
+};
--- /dev/null
+++ tools/altperl/uninstall_node.pl
@@ -0,0 +1,26 @@
+#!/usr/bin/perl
+# $Id: uninstall_node.pl,v 1.1 2004/07/25 04:02:51 cbbrowne Exp $
+# Author: Christopher Browne
+# Copyright 2004 Afilias Canada
+
+require 'slon-tools.pm';
+require 'slon.env';
+#use Pg;
+open(SLONIK, "|slonik");
+print SLONIK genheader();
+print SLONIK qq{
+ uninstall node (id=1);
+};
+close SLONIK;
+
+foreach my $node (@NODES) {
+ foreach my $command ("drop schema _$SETNAME cascade;") {
+ print $command, "\n";
+ print `echo "$command" | psql -h $HOST[$node] -U $USER[$node] -d $DBNAME[$node] -p $PORT[$node]`;
+ }
+ foreach my $t (@SERIALTABLES) {
+ my $command = "alter table $t drop column \\\"_Slony-I_" . $SETNAME . "_rowID\\\";";
+ print $command, "\n";
+ print `echo "$command" | psql -h $HOST[$node] -U $USER[$node] -d $DBNAME[$node] -p $PORT[$node]`;
+ }
+}
--- /dev/null
+++ tools/altperl/slon_watchdog.pl
@@ -0,0 +1,60 @@
+#!/usr/bin/perl
+# $Id: slon_watchdog.pl,v 1.1 2004/07/25 04:02:51 cbbrowne Exp $
+# Author: Christopher Browne
+# Copyright 2004 Afilias Canada
+
+require 'slon-tools.pm';
+require 'slon.env';
+
+$node =$ARGV[0];
+$sleep =$ARGV[1];
+
+if ( scalar(@ARGV) < 2 ) {
+ die "Usage: ./slon_watchdog node sleep-time\n";
+}
+
+slon_watchdog();
+
+sub slon_watchdog {
+ get_pid();
+ if (!($pid)) {
+ if ($node eq "node1") {
+ open (SLONLOG, ">>$LOGDIR/slon-$DBNAME1.out");
+ print SLONLOG "WATCHDOG: No Slon is running for set $SETNAME!\n";
+ print SLONLOG "WATCHDOG: You ought to check the postmaster and slon for evidence of a crash!\n";
+ print SLONLOG "WATCHDOG: I'm going to restart slon for $node...\n";
+ #first restart the node
+ system "./restart_node.sh";
+ system "$SLON_BIN_PATH/slon $SETNAME -s 1000 -d2 'dbname=$DBNAME1 port=$DBPORT1' 2>$LOGDIR/slon-$DBNAME1.err >$LOGDIR/slon-$DBNAME1.out &";
+ get_pid();
+ print SLONLOG "WATCHDOG: Restarted slon for set $SETNAME, PID $pid\n";
+ } elsif ($node eq "node2") {
+ open (SLONLOG, ">>$LOGDIR/slon-$DBNAME2.out");
+ print SLONLOG "WATCHDOG: No Slon is running for set $SETNAME!\n";
+ print SLONLOG "WATCHDOG: You ought to check the postmaster and slon for evidence of a crash!\n";
+ print SLONLOG "WATCHDOG: I'm going to restart slon for $node...\n";
+ #first restart the node
+ system "./restart_node.sh";
+ system "$SLON_BIN_PATH/slon $SETNAME -s 1000 -d2 'dbname=$DBNAME2 port=$DBPORT2' 2>$LOGDIR/slon-$DBNAME2.err >$LOGDIR/slon-$DBNAME2.out &";
+ get_pid();
+ print SLONLOG "Restarted slon for set $SETNAME, PID $pid\n";
+ }
+ } else {
+ open(LOG, ">>$LOGDIR/slon_watchdog.log");
+ print LOG "\n";
+ system "date >> $LOGDIR/slon_watchdog.log";
+ print LOG "Found slon daemon running for set $SETNAME, PID $pid\n";
+ print LOG "Looks Ok\n";
+ print LOG "Sleeping for $sleep seconds\n";
+ }
+ close(PSOUT);
+ sleep $sleep;
+ slon_watchdog();
+}
+
+sub get_pid {
+ open(PSOUT, "ps -auxww | grep -v grep | grep \"slon $SETNAME\" | sort -n | awk '{print \$2}'|");
+ $pid = <PSOUT>;
+ chop $pid;
+ close(PSOUT);
+}
--- /dev/null
+++ tools/altperl/move_set.pl
@@ -0,0 +1,52 @@
+#!/usr/bin/perl
+# $Id: move_set.pl,v 1.1 2004/07/25 04:02:50 cbbrowne Exp $
+# Author: Christopher Browne
+# Copyright 2004 Afilias Canada
+
+require 'slon-tools.pm';
+require 'slon.env';
+
+my ($set, $node1, $node2) = @ARGV;
+if ($set =~ /^set(\d+)$/) {
+ # Node name is in proper form
+ $set = $1;
+} else {
+ print "Valid set names are set1, set2, ...\n\n";
+ die "Usage: ./move_set.pl setN nodeOLD nodeNEW\n";
+}
+
+if ($node1 =~ /^node(\d+)$/) {
+ $node1 = $1;
+} else {
+ print "Valid node names are node1, node2, ...\n\n";
+ die "Usage: ./move_set.pl setN nodeOLD nodeNEW\n";
+}
+if ($node2 =~ /^node(\d+)$/) {
+ $node2 = $1;
+} else {
+ print "Valid node names are node1, node2, ...\n\n";
+ die "Usage: ./move_set.pl setN nodeOLD nodeNEW\n";
+}
+
+open(SLONIK, ">/tmp/slonik.$$");
+print SLONIK genheader();
+my ($dbname, $dbhost)=($DBNAME[1], $HOST[1]);
+print SLONIK qq[
+ try {
+ echo 'Locking down set $set on node $node1';
+ lock set (id = $set, origin = $node1);
+ echo 'Locked down - moving it';
+ move set (id = $set, old origin = $node1, new origin = $node2);
+ unlock set (id = $set, origin = $node2);
+ }
+ on error {
+ echo 'Failure to move set $set from $node1 to $node2';
+ unlock set (id = $set, origin = $node1);
+ exit 1;
+ }
+ echo 'Replication set $set moved from node $node1 to $node2';
+];
+
+close SLONIK;
+`slonik < /tmp/slonik.$$`;
+unlink("/tmp/slonik.$$");
--- /dev/null
+++ tools/altperl/slon_pushsql.pl
@@ -0,0 +1,31 @@
+#!/usr/bin/perl
+# $Id: slon_pushsql.pl,v 1.1 2004/07/25 04:02:50 cbbrowne Exp $
+# Author: Christopher Browne
+# Copyright 2004 Afilias Canada
+
+require 'slon-tools.pm';
+require 'slon.env';
+my ($set, $node, $file) = @ARGV;
+if ($set =~ /^set(\d+)$/) {
+ $set = $1;
+} else {
+ print "Invalid set identifier";
+ die "Usage: ./slon_pushsql.pl set[N] node[N] sql_script_file\n";
+}
+if ($node =~ /^node(\d+)$/) {
+ $node = $1;
+} else {
+ print "Invalid node identifier";
+ die "Usage: ./slon_pushsql.pl set[N] node[N] sql_script_file\n";
+}
+
+open(SLONIK, "|slonik");
+print SLONIK genheader();
+
+print SLONIK qq{
+ execute script (
+ set id=$set,
+ filename='$file',
+ event node = $node
+ );
+};
--- /dev/null
+++ tools/altperl/slon_kill.pl
@@ -0,0 +1,47 @@
+#!/usr/bin/perl
+# $Id: slon_kill.pl,v 1.1 2004/07/25 04:02:50 cbbrowne Exp $
+# Kill all slon instances for the current setname
+# Author: Christopher Browne
+# Copyright 2004 Afilias Canada
+
+require 'slon-tools.pm';
+require 'slon.env';
+
+print "slon_kill.pl... Killing all slon and slon_watchdog instances for setname $SETNAME\n";
+print "1. Kill slon watchdogs\n";
+#kill the watchdog
+
+open(PSOUT, "ps auxww | egrep '[s]lon_watchdog' | sort -n | awk '{print \$2}'|");
+$found="n";
+while ($pid = <PSOUT>) {
+ chomp $pid;
+ if (!($pid)){
+ print "No slon_watchdog is running for set $SETNAME!\n";
+ } else {
+ $found="y";
+ system "kill $pid";
+ print "slon_watchdog for set $SETNAME killed - PID [$pid]\n";
+ }
+}
+close(PSOUT);
+if ($found eq 'n') {
+ print "No watchdogs found\n";
+}
+print "\n2. Kill slon processes\n";
+#kill the slon daemon
+$found="n";
+open(PSOUT, "ps auxww | egrep \"[s]lon .*$SETNAME\" | sort -n | awk '{print \$2}'|");
+while ($pid = <PSOUT>) {
+ chomp $pid;
+ if (!($pid)) {
+ print "No Slon is running for set $SETNAME!\n";
+ } else {
+ system "kill -9 $pid";
+ print "Slon for set $SETNAME killed - PID [$pid]\n";
+ $found="y";
+ }
+}
+close(PSOUT);
+if ($found eq 'n') {
+ print "No slon processes found\n";
+}
--- /dev/null
+++ tools/altperl/README
@@ -0,0 +1,64 @@
+README
+$Id: README,v 1.1 2004/07/25 04:02:50 cbbrowne Exp $
+
+Christopher Browne
+Database Administrator
+Afilias Canada
+
+This is a "second system" set of scripts for managing a set of Slony-I
+instances.
+
+Unlike the shell scripts that have been used, previously, it allows
+having an arbitrary number of Slony-I nodes. They are configured in
+slon.env by calling add_node() once for each node that is needed.
+
+slon.env also contains lists of tables that are to be replicated:
+
+ @KEYEDTABLES contains all of the tables that have unique keys
+
+ @SERIALTABLES contains tables that do not have a unique key
+ to which Slony-I will need to add and populate
+ a unique key
+
+ @SEQUENCES lists all of the application sequences that are to be
+ replicated.
+
+Alas, this means that the values are "hardcoded" as far as the tools
+are concerned.
+
+The natural extension to be added to this to make it more flexible
+would be for slon.env to look at an environment variable to see what
+file these lists are found in. That way, you could do something like:
+
+ for i in `seq 10`; do
+ SLONYENV="./set$i.config" ./init_cluster.pl
+ done
+
+Steps to start up replication
+
+0. Dump from source system to destination
+ pg_dump -s -c flex1 | psql flex2
+
+1. Initializes the Slony cluster
+ ./init_cluster.pl
+
+ This sets up a FULL cross-join set of paths and listeners, doing
+ something of a shortest-path evaluation of which "store listens" to
+ set up.
+
+2. Start up slon servers for both DB instances
+ ./slon_start.pl node1
+ ./slon_start.pl node2
+
+3. Sets up all the tables for "set 1" for FlexReg 2.0
+ ./create_set.pl set1
+
+4. Subscribe Node #2 to Set #1
+ ./subscribe_set.pl set1 node2
+ This is the Big One...
+
+That SHOULD be it, although "should" is probably too strong a word :-)
+
+There are numerous other tools for adding/dropping Slony-I
+configuration, and scripts that might manage simple forms of
+switchover/failover.
- Previous message: [Slony1-commit] By cbbrowne: New Directory
- Next message: [Slony1-commit] By darcyb: Work around braindead m4 processors on some OS's also to be
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
More information about the Slony1-commit mailing list