summaryrefslogtreecommitdiff
path: root/scripts/keepalived
diff options
context:
space:
mode:
authorStig Thormodsrud <stig@vyatta.com>2008-06-06 13:47:36 -0700
committerStig Thormodsrud <stig@vyatta.com>2008-06-06 13:47:36 -0700
commitf498c7b59b8a4784c14b3affcb2d796ab3814138 (patch)
tree4a870cc9ac25ed5a1b573d27616f52a8ba996e3a /scripts/keepalived
parentfff0ed76b20569d50f8e2aca1500602ab6686b21 (diff)
downloadvyatta-cfg-quagga-f498c7b59b8a4784c14b3affcb2d796ab3814138.tar.gz
vyatta-cfg-quagga-f498c7b59b8a4784c14b3affcb2d796ab3814138.zip
Fix 787: Add a command to force vrrp state transition to backup
Diffstat (limited to 'scripts/keepalived')
-rwxr-xr-xscripts/keepalived/VyattaKeepalived.pm36
-rw-r--r--scripts/keepalived/vyatta-clear-vrrp.pl305
-rwxr-xr-xscripts/keepalived/vyatta-keepalived.pl58
3 files changed, 348 insertions, 51 deletions
diff --git a/scripts/keepalived/VyattaKeepalived.pm b/scripts/keepalived/VyattaKeepalived.pm
index c9abe49e..6507d8f7 100755
--- a/scripts/keepalived/VyattaKeepalived.pm
+++ b/scripts/keepalived/VyattaKeepalived.pm
@@ -48,7 +48,7 @@ sub vrrp_log {
sub is_running {
if (-f $keepalived_pid) {
my $pid = `cat $keepalived_pid`;
- chomp $pid;
+ $pid =~ s/\s+$//; # chomp doesn't remove nl
my $ps = `ps -p $pid -o comm=`;
if (defined($ps) && $ps ne "") {
@@ -70,6 +70,7 @@ sub start_daemon {
sub stop_daemon {
if (is_running()) {
my $pid = `cat $keepalived_pid`;
+ $pid =~ s/\s+$//; # chomp doesn't remove nl
system("kill $pid");
vrrp_log("stop_daemon");
} else {
@@ -82,7 +83,7 @@ sub restart_daemon {
if (VyattaKeepalived::is_running()) {
my $pid = `cat $keepalived_pid`;
- chomp $pid;
+ $pid =~ s/\s+$//; # chomp doesn't remove nl
system("kill -1 $pid");
vrrp_log("restart_deamon");
} else {
@@ -216,6 +217,7 @@ sub snoop_for_master {
sub vrrp_state_parse {
my ($file) = @_;
+ $file =~ s/\s+$//; # chomp doesn't remove nl
if ( -f $file) {
my $line = `cat $file`;
chomp $line;
@@ -226,4 +228,34 @@ sub vrrp_state_parse {
}
}
+sub vrrp_get_init_state {
+ my ($intf, $group, $vips, $preempt) = @_;
+
+ my $init_state;
+ if (VyattaKeepalived::is_running()) {
+ my @state_files = VyattaKeepalived::get_state_files($intf, $group);
+ chomp @state_files;
+ if (scalar(@state_files) > 0) {
+ my ($start_time, $f_intf, $f_group, $state, $ltime) =
+ VyattaKeepalived::vrrp_state_parse($state_files[0]);
+ if ($state eq "master") {
+ $init_state = 'MASTER';
+ } else {
+ $init_state = 'BACKUP';
+ }
+ return $init_state;
+ }
+ # fall through to logic below
+ }
+
+ if ($preempt eq "false") {
+ $init_state = 'BACKUP';
+ } else {
+ $init_state = 'MASTER';
+ }
+
+ return $init_state;
+}
+
+1;
#end of file
diff --git a/scripts/keepalived/vyatta-clear-vrrp.pl b/scripts/keepalived/vyatta-clear-vrrp.pl
new file mode 100644
index 00000000..be33f2b9
--- /dev/null
+++ b/scripts/keepalived/vyatta-clear-vrrp.pl
@@ -0,0 +1,305 @@
+#!/usr/bin/perl
+#
+# Module: vyatta-clear-vrrp.pl
+#
+# **** License ****
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# 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.
+#
+# This code was originally developed by Vyatta, Inc.
+# Portions created by Vyatta are Copyright (C) 2007 Vyatta, Inc.
+# All Rights Reserved.
+#
+# Author: Stig Thormodsrud
+# Date: May 2008
+# Description: Script to clear vrrp
+#
+# **** End License ****
+#
+
+use lib "/opt/vyatta/share/perl5/";
+use VyattaKeepalived;
+use Getopt::Long;
+use Sys::Syslog qw(:standard :macros);
+
+use strict;
+use warnings;
+
+my $conf_file = VyattaKeepalived::get_conf_file();
+
+
+sub keepalived_write_file {
+ my ($file, $data) = @_;
+
+ open(my $fh, '>', $file) || die "Couldn't open $file - $!";
+ print $fh $data;
+ close $fh;
+}
+
+sub set_instance_inital_state {
+ my ($instance, $init) = @_;
+
+ if ($init eq "MASTER" and $instance =~ /state \s+ BACKUP/ix) {
+ if ($instance !~ s/state \s+ BACKUP/state MASTER/ix) {
+ print "Error: unable to replace BACKUP/MASTER\n";
+ }
+ } elsif ($init eq "BACKUP" and $instance =~ /state \s+ MASTER/ix) {
+ if ($instance !~ s/state \s+ MASTER/state BACKUP/ix) {
+ print "Error: unable to replace MASTER/BACKUP\n";
+ }
+ }
+ return $instance;
+}
+
+my $brace_block;
+
+sub vrrp_extract_instance {
+ my ($conf, $instance) = @_;
+
+ #
+ # regex to find a balanced group of squiggly braces {{{ }}}
+ #
+ $brace_block = qr/
+ \{ # 1st brace
+ (
+ [^\{\}]+ # anything but brace
+ | # or
+ (??{ $brace_block }) # another brace_block
+ )*
+ \} # matching brace
+ /x;
+
+ #
+ # regex to match instance:
+ #
+ # vrrp_instance vyatta-eth1.100-15 {
+ # state MASTER
+ # interface eth1
+ # virtual_router_id 15
+ # virtual_ipaddress {
+ # 1.1.1.1
+ # }
+ # }
+ #
+ my $instance_regex = qr/(vrrp_instance \s+ $instance \s+ $brace_block)/x;
+
+ #
+ # replace the instance with nothing
+ #
+ my $match_instance;
+ if ($conf =~ s/($instance_regex)//) {
+ $match_instance = $1;
+ } else {
+ return ($conf, undef);
+ }
+
+ return ($conf, $match_instance);
+}
+
+sub get_vrrp_intf_group {
+ my @array;
+
+ #
+ # return an array of hashes that contains all the intf/group pairs
+ #
+
+ my $config = new VyattaConfig;
+ $config->setLevel("interfaces ethernet");
+ my @eths = $config->listOrigNodes();
+ foreach my $eth (@eths) {
+ my $path = "interfaces ethernet $eth";
+ $config->setLevel($path);
+ if ($config->existsOrig("vrrp")) {
+ $path = "$path vrrp vrrp-group";
+ $config->setLevel($path);
+ my @groups = $config->listOrigNodes();
+ foreach my $group (@groups) {
+ my %hash;
+ $hash{'intf'} = $eth;
+ $hash{'group'} = $group;
+ $hash{'path'} = "$path $group";
+ push @array, {%hash};
+ }
+ }
+
+ $path = "interfaces ethernet $eth";
+ $config->setLevel($path);
+ if ($config->existsOrig("vif")) {
+ my $path = "$path vif";
+ $config->setLevel($path);
+ my @vifs = $config->listOrigNodes();
+ foreach my $vif (@vifs) {
+ my $vif_intf = $eth . "." . $vif;
+ my $vif_path = "$path $vif";
+ $config->setLevel($vif_path);
+ if ($config->existsOrig("vrrp")) {
+ $vif_path = "$vif_path vrrp vrrp-group";
+ $config->setLevel($vif_path);
+ my @groups = $config->listOrigNodes();
+ foreach my $group (@groups) {
+ my %hash;
+ $hash{'intf'} = $vif_intf;
+ $hash{'group'} = $group;
+ $hash{'path'} = "$path $group";
+ push @array, {%hash};
+ }
+ }
+ }
+ }
+ }
+
+ return @array;
+}
+
+sub set_inital_state {
+ my $conf = shift;
+
+ my $new_conf = '';
+
+ #
+ # find all intf/groups, extract instance, set init state
+ #
+ my @vrrp_instances = get_vrrp_intf_group();
+
+ foreach my $hash (@vrrp_instances) {
+ my $intf = $hash->{'intf'};
+ my $group = $hash->{'group'};
+ my $instance = "vyatta-" . "$intf" . "-" . "$group";
+ my ($tmp_conf, $match_instance) =
+ vrrp_extract_instance($conf, $instance);
+ if (defined $match_instance) {
+ my $init = VyattaKeepalived::vrrp_get_init_state($intf, $group,
+ "", "false");
+ $match_instance = set_instance_inital_state($match_instance, $init);
+ $new_conf .= $match_instance . "\n\n";
+ }
+ }
+
+ return $new_conf;
+}
+
+
+#
+# main
+#
+my ($action, $vrrp_intf, $vrrp_group);
+
+GetOptions("vrrp-action=s" => \$action,
+ "intf=s" => \$vrrp_intf,
+ "group=s" => \$vrrp_group);
+
+if (! defined $action) {
+ print "no action\n";
+ exit 1;
+}
+
+openlog($0, "", LOG_USER);
+my $login = getlogin();
+
+#
+# clear_process
+#
+if ($action eq "clear_process") {
+ syslog("warning", "clear vrrp process requested by $login");
+ if (VyattaKeepalived::is_running()) {
+ print "Restarting VRRP...\n";
+ VyattaKeepalived::restart_daemon(VyattaKeepalived::get_conf_file());
+ } else {
+ print "Starting VRRP...\n";
+ VyattaKeepalived::start_daemon(VyattaKeepalived::get_conf_file());
+ }
+ exit 0;
+}
+
+#
+# clear_master
+#
+if ($action eq "clear_master") {
+
+ #
+ # The kludge here to force a vrrp instance to switch from master to
+ # backup is to read the keepalived config, remove the instance to be
+ # cleared, signal the daemon to reread it's config. This will cause
+ # keepalived to see the old instance missing and send a priorty 0
+ # advert to cause the backup to immediately take over master. Once
+ # that is done we put back the orginal config and signal the daemon
+ # again. Note: if the instance if preempt=true, then it may immediately
+ # try to become master again.
+ #
+
+ if (! defined $vrrp_intf || ! defined $vrrp_group) {
+ print "must include interface & group\n";
+ exit 1;
+ }
+
+ my $instance = "vyatta-" . "$vrrp_intf" . "-" . "$vrrp_group";
+ my $state_file = VyattaKeepalived::get_state_file($vrrp_intf, $vrrp_group);
+ if (! -f $state_file) {
+ print "Invalid interface/group [$vrrp_intf][$vrrp_group]\n";
+ exit 1;
+ }
+
+ my ($start_time, $intf, $group, $state, $ltime) =
+ VyattaKeepalived::vrrp_state_parse($state_file);
+ if ($state ne "master") {
+ print "vrrp group $vrrp_group on $vrrp_intf is already in backup\n";
+ exit 1;
+ }
+
+ syslog("warning", "clear vrrp master [$instance] requested by $login");
+ VyattaKeepalived::vrrp_log("vrrp clear_master $vrrp_intf $vrrp_group");
+
+ # should add a file lock
+ local($/, *FILE); # slurp mode
+ open FILE, "<", $conf_file or die "Couldn't open $conf_file\n";
+ my $conf = <FILE>;
+ close FILE;
+
+ my ($new_conf, $match_instance) = vrrp_extract_instance($conf, $instance);
+ if ($match_instance !~ /nopreempt/) {
+ print "Warning: $instance is in preempt mode";
+ print " and may retake master\n";
+ }
+ $match_instance = set_instance_inital_state($match_instance, "BACKUP");
+
+ #
+ # need to set the correct initial state for the remaining instances
+ #
+ $new_conf = set_inital_state($new_conf);
+
+ #
+ # create the temporary config file
+ #
+ my $tmp_conf_file = $conf_file . ".$$";
+ keepalived_write_file($tmp_conf_file, $new_conf);
+
+ my $conf_file_bak = $conf_file . ".bak";
+ system("mv $conf_file $conf_file_bak");
+ system("cp $tmp_conf_file $conf_file");
+
+ VyattaKeepalived::restart_daemon($conf_file);
+
+ print "Forcing $vrrp_intf-$group to BACKUP...\n";
+ sleep(3);
+
+ #
+ # add modified instance back and restart
+ #
+ $new_conf .= "\n" . $match_instance . "\n";
+
+ keepalived_write_file($conf_file, $new_conf);
+ VyattaKeepalived::restart_daemon($conf_file);
+
+ system("rm $conf_file_bak $tmp_conf_file");
+ exit 0;
+}
+
+exit 0;
+
+# end of file
diff --git a/scripts/keepalived/vyatta-keepalived.pl b/scripts/keepalived/vyatta-keepalived.pl
index ac92ca8e..e40c737a 100755
--- a/scripts/keepalived/vyatta-keepalived.pl
+++ b/scripts/keepalived/vyatta-keepalived.pl
@@ -36,33 +36,6 @@ my $conf_file = VyattaKeepalived::get_conf_file();
my %HoA_sync_groups;
-sub vrrp_get_init_state {
- my ($intf, $group, $vips, $preempt) = @_;
-
- my $init_state;
- if (VyattaKeepalived::is_running()) {
- my @state_files = VyattaKeepalived::get_state_files($intf, $group);
- if (scalar(@state_files) > 0) {
- my ($start_time, $f_intf, $f_group, $state, $ltime) =
- VyattaKeepalived::vrrp_state_parse($state_files[0]);
- if ($state eq "master") {
- $init_state = 'MASTER';
- } else {
- $init_state = 'BACKUP';
- }
- return $init_state;
- }
- # fall through to logic below
- }
-
- if ($preempt eq "false") {
- $init_state = 'BACKUP';
- } else {
- $init_state = 'MASTER';
- }
-
- return $init_state;
-}
sub keepalived_get_values {
my ($intf, $path) = @_;
@@ -132,7 +105,9 @@ sub keepalived_get_values {
}
$output .= "vrrp_instance $vrrp_instance \{\n";
- my $init_state = vrrp_get_init_state($intf, $group, $vips[0], $preempt);
+ my $init_state;
+ $init_state = VyattaKeepalived::vrrp_get_init_state($intf, $group,
+ $vips[0], $preempt);
$output .= "\tstate $init_state\n";
$output .= "\tinterface $intf\n";
$output .= "\tvirtual_router_id $group\n";
@@ -151,12 +126,12 @@ sub keepalived_get_values {
$output .= "\t\t$vip\n";
}
$output .= "\t\}\n";
- $output .= "\tnotify_master ";
- $output .= "\"$state_transition_script master $intf $group $run_master_script @vips\" \n";
- $output .= "\tnotify_backup ";
- $output .= "\"$state_transition_script backup $intf $group $run_backup_script @vips\" \n";
- $output .= "\tnotify_fault ";
- $output .= "\"$state_transition_script fault $intf $group $run_fault_script @vips\" \n";
+ $output .= "\tnotify_master \"$state_transition_script master ";
+ $output .= "$intf $group $run_master_script @vips\" \n";
+ $output .= "\tnotify_backup \"$state_transition_script backup ";
+ $output .= "$intf $group $run_backup_script @vips\" \n";
+ $output .= "\tnotify_fault \"$state_transition_script fault ";
+ $output .= "$intf $group $run_fault_script @vips\" \n";
$output .= "\}\n\n";
}
@@ -408,21 +383,6 @@ if ($action eq "delete") {
exit 0;
}
-if ($action eq "clear") {
- if (VyattaKeepalived::is_running()) {
- print "Restarting VRRP...\n";
- VyattaKeepalived::restart_daemon(VyattaKeepalived::get_conf_file());
- } else {
- print "Starting VRRP...\n";
- VyattaKeepalived::start_daemon(VyattaKeepalived::get_conf_file());
- }
- exit 0;
-}
-
exit 0;
# end of file
-
-
-
-