summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Southworth <john.southworth@vyatta.com>2012-05-15 11:34:33 -0700
committerJohn Southworth <john.southworth@vyatta.com>2012-05-15 11:34:33 -0700
commit6325118d9aa1ae7890a29c6f211ce456d04d68a9 (patch)
treed6cbbcad7acb4cd01cf520eff96e1641bd6a175f
parent0da3c8a7e5b7506a4b9a7d1bedbd48fd45e7d89d (diff)
downloadvyatta-op-6325118d9aa1ae7890a29c6f211ce456d04d68a9.tar.gz
vyatta-op-6325118d9aa1ae7890a29c6f211ce456d04d68a9.zip
Add Vyatta wrappers for new keepalived output
1. Move show and clear vrrp scripts from vyatta-cfg-system. These belong in vyatta-op. 2. Create templates for new vrrp commands 3. Make show commands go through a perl module so they can be referenced from the webgui.
-rw-r--r--Makefile.am5
-rw-r--r--lib/Vyatta/VRRP/OPMode.pm366
-rwxr-xr-xscripts/vrrp/vyatta-clear-vrrp.pl303
-rw-r--r--scripts/vrrp/vyatta-show-vrrp.pl114
-rw-r--r--templates/show/vrrp/detail/node.def3
-rw-r--r--templates/show/vrrp/interface/node.tag/group/node.tag/node.def4
-rw-r--r--templates/show/vrrp/interface/node.tag/node.def4
-rw-r--r--templates/show/vrrp/node.def2
-rw-r--r--templates/show/vrrp/statistics/interface/node.def1
-rw-r--r--templates/show/vrrp/statistics/interface/node.tag/group/node.def1
-rw-r--r--templates/show/vrrp/statistics/interface/node.tag/group/node.tag/node.def3
-rw-r--r--templates/show/vrrp/statistics/interface/node.tag/node.def3
-rw-r--r--templates/show/vrrp/statistics/node.def2
-rw-r--r--templates/show/vrrp/sync-group/group/node.def1
-rw-r--r--templates/show/vrrp/sync-group/group/node.tag/node.def3
-rw-r--r--templates/show/vrrp/sync-group/node.def3
16 files changed, 813 insertions, 5 deletions
diff --git a/Makefile.am b/Makefile.am
index 99f5da6..2d82760 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -5,6 +5,7 @@ completion_DATA = etc/bash_completion.d/vyatta-op
opdir = $(datadir)/vyatta-op/templates
bin_sudo_usersdir = $(bindir)/sudo-users
etc_shell_leveldir = $(sysconfdir)/shell/level
+share_perl5dir = $(datarootdir)/perl5/Vyatta/VRRP/
funcdir = $(datadir)/vyatta-op/functions
func_DATA = functions/tech-support
@@ -58,6 +59,10 @@ bin_sudo_users_SCRIPTS += scripts/vyatta-reboot.pl
bin_sudo_users_SCRIPTS += scripts/vyatta-op-dns-forwarding.pl
bin_sudo_users_SCRIPTS += scripts/vyatta-op-dynamic-dns.pl
bin_sudo_users_SCRIPTS += scripts/vyatta-clear-conntrack
+bin_sudo_users_SCRIPTS += scripts/vrrp/vyatta-clear-vrrp.pl
+bin_sudo_users_SCRIPTS += scripts/vrrp/vyatta-show-vrrp.pl
+
+share_perl5_DATA = lib/Vyatta/VRRP/OPMode.pm
all-local:
./gen-unpriv-commands.sh
diff --git a/lib/Vyatta/VRRP/OPMode.pm b/lib/Vyatta/VRRP/OPMode.pm
new file mode 100644
index 0000000..32d86fc
--- /dev/null
+++ b/lib/Vyatta/VRRP/OPMode.pm
@@ -0,0 +1,366 @@
+#
+# Module: Vyatta::VRRP::OPMode
+#
+# **** 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-2012 Vyatta, Inc.
+# All Rights Reserved.
+#
+# Author: John Southworth
+# Date: May 2012
+# Description: Process operational data from keepalived
+#
+# **** End License ****
+#
+
+package Vyatta::VRRP::OPMode;
+use strict;
+use warnings;
+our @EXPORT = qw(process_data process_stats print_summary print_stats print_sync print_detail check_intf);
+use base qw(Exporter);
+
+use Sort::Versions;
+
+my $PIDFILE='/var/run/vrrp.pid';
+my $DATAFILE='/tmp/keepalived.data';
+my $STATSFILE='/tmp/keepalived.stats';
+
+open my $PIDF, '<', $PIDFILE;
+my $PID=<$PIDF>;
+close $PIDF;
+
+sub trim {
+ my $string = shift;
+ $string =~ s/^\s+//;
+ $string =~ s/\s+$//;
+ return $string;
+}
+
+sub conv_name {
+ my $name = shift;
+ $name = trim $name;
+ $name = lc $name;
+ $name =~ s/\s/-/g;
+ return $name;
+}
+
+sub add_to_datahash {
+ my ($dh, $interface, $instance, $in_sync, $name, $val) = @_;
+ $name = conv_name $name;
+ if ($in_sync) {
+ if ($name eq 'monitor'){
+ $dh->{'sync-groups'}->{$instance}->{$name} =
+ [ $dh->{'sync-groups'}->{$instance}->{$name} ?
+ @{$dh->{'sync-groups'}->{$instance}->{$name}} : (),
+ $val
+ ];
+ } else {
+ $dh->{'sync-groups'}->{$instance}->{$name} = $val;
+ }
+ } else {
+ $dh->{'instances'}->{$interface}->{$instance}->{$name} = $val;
+ }
+}
+
+sub process_data {
+ my ($dh) = @_;
+ my ($instance, $interface, $in_sync, $in_vip);
+ kill 'SIGUSR1', $PID;
+ open my $DATA, '<', $DATAFILE;
+ while (<$DATA>)
+ {
+ m/VRRP Instance = vyatta-(.*?)-(.*)/ && do {
+ $interface = $1;
+ $instance = $2;
+ $in_sync = undef;
+ $in_vip = undef;
+ $dh->{'instances'}->{$interface}->{$instance} = {};
+ next;
+ };
+ m/VRRP Sync Group = (.*?), (.*)/ && do {
+ $instance = $1;
+ $interface = undef;
+ $in_vip = undef;
+ my $state = $2;
+ $in_sync = 1;
+ add_to_datahash $dh, $interface, $instance, $in_sync, 'state', $state;
+ next;
+ };
+ if ($in_vip){
+ m/(.*?) dev (.*)/ && do {
+ $dh->{'instances'}->{$interface}->{$instance}->{vips} =
+ [ $dh->{'instances'}->{$interface}->{$instance}->{vips} ?
+ @{$dh->{'instances'}->{$interface}->{$instance}->{vips}} : (),
+ trim $1 ];
+ };
+ }
+ m/(.*?) = (.*)/ && do {
+ $in_vip = undef;
+ add_to_datahash $dh, $interface, $instance, $in_sync, $1, $2;
+ m/Virtual IP/ && do {$in_vip = 1};
+ next;
+ };
+ }
+ close $DATA;
+}
+
+sub elapse_time {
+ my ($start, $stop) = @_;
+
+ my $seconds = $stop - $start;
+ my $string = '';
+ my $secs_min = 60;
+ my $secs_hour = $secs_min * 60;
+ my $secs_day = $secs_hour * 24;
+ my $secs_week = $secs_day * 7;
+
+ my $weeks = int($seconds / $secs_week);
+ if ($weeks > 0 ) {
+ $seconds = int($seconds % $secs_week);
+ $string .= $weeks . "w";
+ }
+ my $days = int($seconds / $secs_day);
+ if ($days > 0) {
+ $seconds = int($seconds % $secs_day);
+ $string .= $days . "d";
+ }
+ my $hours = int($seconds / $secs_hour);
+ if ($hours > 0) {
+ $seconds = int($seconds % $secs_hour);
+ $string .= $hours . "h";
+ }
+ my $mins = int($seconds / $secs_min);
+ if ($mins > 0) {
+ $seconds = int($seconds % $secs_min);
+ $string .= $mins . "m";
+ }
+ $string .= $seconds . "s";
+
+ return $string;
+}
+
+sub find_sync {
+ my ($intf, $vrid, $dh) = @_;
+ my $instance = "vyatta-$intf-$vrid";
+ foreach my $sync (sort versioncmp keys(%{$dh->{'sync-groups'}})){
+ return $sync if (grep { $instance } @{$dh->{'sync-groups'}->{$sync}->{monitor}});
+ }
+ return;
+}
+
+sub check_intf {
+ my ($hash, $intf, $vrid) = @_;
+ if ($intf) {
+ if (!exists($hash->{instances}->{$intf})){
+ print "VRRP is not running on $intf\n";
+ return 1;
+ }
+ if ($vrid){
+ if (!exists($hash->{instances}->{$intf}->{$vrid})){
+ print "No VRRP group $vrid exists on $intf\n";
+ return 1;
+ }
+ }
+ }
+ return;
+}
+
+
+sub print_detail {
+ my ($dh,$intf,$group) = @_;
+ print "--------------------------------------------------\n";
+ foreach my $interface (sort versioncmp keys(%{$dh->{instances}})) {
+ next if ($intf && $interface ne $intf);
+ printf "Interface: %s\n", $interface;
+ printf "--------------\n";
+ foreach my $vrid (sort versioncmp keys(%{$dh->{instances}->{$interface}})){
+ next if ($group && $vrid ne $group);
+ printf " Group: %s\n", $vrid;
+ printf " ----------\n";
+ printf " State:\t\t\t%s\n",
+ $dh->{instances}->{$interface}->{$vrid}->{state};
+ printf " Last transition:\t\t%s\n",
+ elapse_time($dh->{instances}->{$interface}->{$vrid}->{'last-transition'}, time);
+ printf "\n";
+ if ( $dh->{instances}->{$interface}->{$vrid}->{state} eq 'BACKUP') {
+ printf " Master router:\t\t%s\n",
+ $dh->{instances}->{$interface}->{$vrid}->{'master-router'};
+ printf " Master priority:\t\t%s\n",
+ $dh->{instances}->{$interface}->{$vrid}->{'master-priority'};
+ printf "\n";
+ }
+ if ($dh->{instances}->{$interface}->{$vrid}->{'transmitting-device'} ne
+ $dh->{instances}->{$interface}->{$vrid}->{'listening-device'}){
+ printf " RFC 3768 Compliant\n";
+ printf " Virtual MAC interface:\t%s\n",
+ $dh->{instances}->{$interface}->{$vrid}->{'transmitting-device'};
+ printf " Address Owner:\t\t%s\n",
+ ($dh->{instances}->{$interface}->{$vrid}->{priority} == 255) ? 'yes': 'no';
+ printf "\n";
+ }
+ printf " Source Address:\t\t%s\n",
+ $dh->{instances}->{$interface}->{$vrid}->{'using-mcast-src_ip'};
+ printf " Priority:\t\t\t%s\n",
+ $dh->{instances}->{$interface}->{$vrid}->{'priority'};
+ printf " Advertisement interval:\t%s\n",
+ $dh->{instances}->{$interface}->{$vrid}->{'advert-interval'};
+ printf " Authentication type:\t\t%s\n",
+ $dh->{instances}->{$interface}->{$vrid}->{'authentication-type'};
+ printf " Preempt:\t\t\t%s\n",
+ $dh->{instances}->{$interface}->{$vrid}->{'preempt'};
+ printf "\n";
+ my $sync = find_sync($interface, $vrid, $dh);
+ if ($sync) {
+ printf " Sync-group:\t\t\t%s\n", $sync;
+ printf "\n";
+ }
+ printf " VIP count:\t\t\t%s\n",
+ $dh->{instances}->{$interface}->{$vrid}->{'virtual-ip'};
+ foreach my $vip (@{$dh->{instances}->{$interface}->{$vrid}->{vips}}){
+ printf " %s\n", $vip;
+ }
+ printf "\n";
+ }
+ }
+}
+
+sub print_summary {
+ my ($dh, $intf, $group) = @_;
+ my $format = "%-18s%-7s%-8s%-11s%-7s%-12s%s\n";
+ printf $format, '','','','RFC','Addr','Last','Sync';
+ printf $format, 'Interface','Group','State','Compliant','Owner','Transition','Group';
+ printf $format, '---------','-----','-----','---------','-----','----------','-----';
+ foreach my $interface (sort versioncmp keys(%{$dh->{instances}})) {
+ next if ($intf && $interface ne $intf);
+ foreach my $vrid (sort versioncmp keys(%{$dh->{instances}->{$interface}})){
+ next if ($group && $vrid ne $group);
+ my $state = $dh->{instances}->{$interface}->{$vrid}->{state};
+ my $compliant =
+ ($dh->{instances}->{$interface}->{$vrid}->{'transmitting-device'} ne
+ $dh->{instances}->{$interface}->{$vrid}->{'listening-device'}) ? 'yes': 'no';
+ my $addr_owner = ($dh->{instances}->{$interface}->{$vrid}->{priority} == 255) ? 'yes': 'no';
+ my $lt = elapse_time($dh->{instances}->{$interface}->{$vrid}->{'last-transition'}, time);
+ my $sync = find_sync($interface, $vrid, $dh);
+ $sync = "<none>" if (!defined($sync));
+ printf $format, $interface, $vrid, $state, $compliant, $addr_owner, $lt, $sync;
+ }
+ }
+ printf "\n";
+}
+
+sub process_stats {
+ my ($sh) = @_;
+ my ($instance, $interface, $section);
+ kill 'SIGUSR2', $PID;
+ open my $STATS, '<', $STATSFILE;
+ while (<$STATS>)
+ {
+ m/VRRP Instance: vyatta-(.*?)-(.*)/ && do {
+ $interface = $1;
+ $instance = $2;
+ $sh->{'instances'}->{$interface}->{$instance} = {};
+ next;
+ };
+ m/Released master: (.*)/ && do {
+ $sh->{'instances'}->{$interface}->{$instance}->{'released-master'} = $1;
+ next;
+ };
+ m/Became master: (.*)/ && do {
+ $sh->{'instances'}->{$interface}->{$instance}->{'became-master'} = $1;
+ next;
+ };
+ m/(.*?):$/ && do {
+ $section = conv_name $1;
+ $sh->{'instances'}->{$interface}->{$instance}->{$section} = {};
+ next;
+ };
+ m/(.*?): (.*)/ && do {
+ my $id = conv_name $1;
+ $sh->{'instances'}->{$interface}->{$instance}->{$section}->{$id} = $2;
+ next;
+ };
+ print $_;
+ }
+
+ close $STATS;
+}
+
+sub print_stats {
+ my ($sh, $intf, $group) = @_;
+ print "--------------------------------------------------\n";
+ foreach my $interface (sort versioncmp keys(%{$sh->{instances}})) {
+ next if ($intf && $interface ne $intf);
+ printf "Interface: %s\n", $interface;
+ printf "--------------\n";
+ foreach my $vrid (sort versioncmp keys(%{$sh->{instances}->{$interface}})){
+ next if ($group && $vrid ne $group);
+ printf " Group: %s\n", $vrid;
+ printf " ----------\n";
+ printf " Advertisements:\n";
+ printf " Received:\t\t\t%d\n",
+ $sh->{instances}->{$interface}->{$vrid}->{advertisements}->{received};
+ printf " Sent:\t\t\t%d\n",
+ $sh->{instances}->{$interface}->{$vrid}->{advertisements}->{sent};
+ printf "\n";
+ printf " Became master:\t\t%d\n",
+ $sh->{instances}->{$interface}->{$vrid}->{'became-master'};
+ printf " Released master:\t\t%d\n",
+ $sh->{instances}->{$interface}->{$vrid}->{'released-master'};
+ printf "\n";
+ printf " Packet errors:\n";
+ printf " Length:\t\t\t%d\n",
+ $sh->{instances}->{$interface}->{$vrid}->{'packet-errors'}->{length};
+ printf " TTL:\t\t\t%d\n",
+ $sh->{instances}->{$interface}->{$vrid}->{'packet-errors'}->{ttl};
+ printf " Invalid type:\t\t%d\n",
+ $sh->{instances}->{$interface}->{$vrid}->{'packet-errors'}->{'invalid-type'};
+ printf " Advertisement interval:\t%d\n",
+ $sh->{instances}->{$interface}->{$vrid}->{'packet-errors'}->{'advertisement-interval'};
+ printf " Address List:\t\t%d\n",
+ $sh->{instances}->{$interface}->{$vrid}->{'packet-errors'}->{'address-list'};
+ printf "\n";
+ printf " Authentication Errors:\n";
+ printf " Invalid type:\t\t%d\n",
+ $sh->{instances}->{$interface}->{$vrid}->{'authentication-errors'}->{'invalid-type'};
+ printf " Type mismatch:\t\t%d\n",
+ $sh->{instances}->{$interface}->{$vrid}->{'authentication-errors'}->{'type-mismatch'};
+ printf " Failure:\t\t\t%d\n",
+ $sh->{instances}->{$interface}->{$vrid}->{'authentication-errors'}->{'failure'};
+ printf "\n";
+ printf " Priority Zero Advertisements:\n";
+ printf " Received\t\t\t%d\n",
+ $sh->{instances}->{$interface}->{$vrid}->{'priority-zero'}->{'received'};
+ printf " Sent\t\t\t%d\n",
+ $sh->{instances}->{$interface}->{$vrid}->{'priority-zero'}->{'sent'};
+ printf "\n";
+ }
+ }
+}
+
+sub print_sync {
+ my ($dh, $sync_group) = @_;
+ print "--------------------------------------------------\n";
+ foreach my $sync (sort versioncmp keys(%{$dh->{'sync-groups'}})){
+ next if ($sync_group && $sync ne $sync_group);
+ printf "Group: %s\n", $sync;
+ printf "---------\n";
+ printf " State: %s\n", $dh->{'sync-groups'}->{$sync}->{state};
+ printf " Monitoring:\n";
+ foreach my $mon (@{$dh->{'sync-groups'}->{$sync}->{monitor}}){
+ my ($intf, $vrid) = $mon =~ m/vyatta-(.*?)-(.*)/;
+ printf " Interface: %s, Group: %s\n", $intf, $vrid;
+ }
+ printf "\n";
+ }
+}
+
+1;
diff --git a/scripts/vrrp/vyatta-clear-vrrp.pl b/scripts/vrrp/vyatta-clear-vrrp.pl
new file mode 100755
index 0000000..34c0327
--- /dev/null
+++ b/scripts/vrrp/vyatta-clear-vrrp.pl
@@ -0,0 +1,303 @@
+#!/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-2009 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 Vyatta::Keepalived;
+use Vyatta::Interface;
+use Vyatta::Misc;
+
+use Getopt::Long;
+use Sys::Syslog qw(:standard :macros);
+
+use strict;
+use warnings;
+
+my $conf_file = 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 Vyatta::Config;
+
+ foreach my $name ( getInterfaces() ) {
+ my $intf = new Vyatta::Interface($name);
+ next unless $intf;
+ my $path = $intf->path();
+ $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'} = $name;
+ $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();
+
+ my $tmp_conf = $conf;
+ foreach my $hash (@vrrp_instances) {
+ my $intf = $hash->{'intf'};
+ my $group = $hash->{'group'};
+ my $instance = 'vyatta-' . "$intf" . '-' . "$group";
+ my $match_instance;
+ ($tmp_conf, $match_instance) =
+ vrrp_extract_instance($tmp_conf, $instance);
+ if (defined $match_instance) {
+ my $init = vrrp_get_init_state($intf, $group, '', 'false');
+ $match_instance = set_instance_inital_state($match_instance, $init);
+ $new_conf .= $match_instance . "\n\n";
+ }
+ }
+ $new_conf = $tmp_conf . $new_conf;
+
+ 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 (Vyatta::Keepalived::is_running()) {
+ print "Restarting VRRP...\n";
+ restart_daemon(get_conf_file());
+ } else {
+ print "Starting VRRP...\n";
+ start_daemon(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 = Vyatta::Keepalived::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) =
+ Vyatta::Keepalived::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");
+ Vyatta::Keepalived::vrrp_log("vrrp clear_master $vrrp_intf $vrrp_group");
+
+ # should add a file lock
+ local($/); # slurp mode
+ open my $f, '<', $conf_file or die "Couldn't open $conf_file\n";
+ my $conf = <$f>;
+ close $f;
+
+ my $sync_group = list_vrrp_sync_group($intf, $group);
+ my @instances = ();
+ if (defined($sync_group)) {
+ print "vrrp group $vrrp_group on $vrrp_intf is in sync-group "
+ . "$sync_group\n";
+ @instances = list_vrrp_sync_group_members($sync_group);
+ } else {
+ push @instances, $instance;
+ }
+
+ my $new_conf = $conf;
+ my $clear_instances;
+ foreach my $inst (@instances) {
+ my $match_instance;
+ print "Forcing $inst to BACKUP...\n";
+ Vyatta::Keepalived::vrrp_log("vrrp extract $inst");
+ ($new_conf, $match_instance) = vrrp_extract_instance($new_conf, $inst);
+ 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');
+ $clear_instances .= "$match_instance\n";
+ }
+
+ #
+ # 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");
+
+ restart_daemon($conf_file);
+
+ sleep(3);
+
+ #
+ # add modified instance back and restart
+ #
+ $new_conf .= "\n" . $clear_instances . "\n";
+
+ keepalived_write_file($conf_file, $new_conf);
+ Vyatta::Keepalived::restart_daemon($conf_file);
+
+ system("rm $conf_file_bak $tmp_conf_file");
+ exit 0;
+}
+
+exit 0;
+
+# end of file
diff --git a/scripts/vrrp/vyatta-show-vrrp.pl b/scripts/vrrp/vyatta-show-vrrp.pl
new file mode 100644
index 0000000..afc490b
--- /dev/null
+++ b/scripts/vrrp/vyatta-show-vrrp.pl
@@ -0,0 +1,114 @@
+#!/usr/bin/env perl
+#
+# **** 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-2012 Vyatta, Inc.
+# All Rights Reserved.
+#
+# Author: John Southworth
+# Date: May 2012
+# Description: Process operational data from keepalived
+#
+# **** End License ****
+#
+
+use strict;
+use lib "/opt/vyatta/share/perl5";
+
+use Getopt::Long;
+use Vyatta::VRRP::OPMode;
+use Sort::Versions;
+use v5.10;
+
+my ($show, $intf, $vrid);
+GetOptions("show=s" => \$show,
+ "intf=s" => \$intf,
+ "vrid=s" => \$vrid
+ );
+
+sub list_vrrp_intf {
+ my $intf = shift;
+ my $hash = {};
+ process_data $hash;
+ if ($intf) {
+ printf "%s\n", join " ", sort versioncmp keys(%{$hash->{instances}->{$intf}});
+ } else {
+ printf "%s\n", join " ", sort versioncmp keys(%{$hash->{instances}});
+ }
+}
+
+sub list_vrrp_sync_groups {
+ my $hash = {};
+ process_data $hash;
+ printf "%s\n", join " ", sort versioncmp keys(%{$hash->{'sync-groups'}});
+}
+
+sub show_vrrp_summary {
+ my ($intf, $vrid) = @_;
+ my $hash = {};
+ process_data $hash;
+ return if (check_intf($hash, $intf, $vrid));
+ print_summary $hash, $intf, $vrid;
+}
+
+sub show_vrrp_stats {
+ my ($intf, $vrid) = @_;
+ my $hash = {};
+ process_stats $hash;
+ return if (check_intf($hash, $intf, $vrid));
+ print_stats $hash, $intf, $vrid;
+}
+
+sub show_vrrp_detail {
+ my ($intf, $vrid) = @_;
+ my $hash = {};
+ process_data $hash;
+ return if (check_intf($hash, $intf, $vrid));
+ print_detail $hash, $intf, $vrid;
+}
+
+sub show_vrrp_sync_groups {
+ my $sync = shift;
+ my $hash = {};
+ process_data $hash;
+ if ($sync && !exists($hash->{'sync-groups'}->{$sync})){
+ print "Sync-group: $sync does not exist\n";
+ return;
+ }
+ print_sync $hash, $intf;
+}
+
+given ($show) {
+ when ('summary') {
+ show_vrrp_summary $intf, $vrid;
+ }
+ when ('detail') {
+ show_vrrp_detail $intf, $vrid;
+ }
+ when ('stats') {
+ show_vrrp_stats $intf, $vrid;
+ }
+ when ('sync') {
+ show_vrrp_sync_groups $intf;
+ }
+ when ('interface') {
+ list_vrrp_intf $intf;
+ }
+ when ('syncs') {
+ list_vrrp_sync_groups;
+ }
+ default {
+ exit;
+ }
+}
+
+
diff --git a/templates/show/vrrp/detail/node.def b/templates/show/vrrp/detail/node.def
new file mode 100644
index 0000000..269df73
--- /dev/null
+++ b/templates/show/vrrp/detail/node.def
@@ -0,0 +1,3 @@
+help: Show detailed VRRP information
+run: /opt/vyatta/bin/sudo-users/vyatta-show-vrrp.pl --show=detail
+
diff --git a/templates/show/vrrp/interface/node.tag/group/node.tag/node.def b/templates/show/vrrp/interface/node.tag/group/node.tag/node.def
index de7eb12..c0df0f2 100644
--- a/templates/show/vrrp/interface/node.tag/group/node.tag/node.def
+++ b/templates/show/vrrp/interface/node.tag/group/node.tag/node.def
@@ -1,3 +1,3 @@
help: Show VRRP information for specified interface and group
-allowed: /opt/vyatta/sbin/vyatta-keepalived.pl --vrrp-action=list-vrrp-group --intf "${COMP_WORDS[COMP_CWORD-2]}"
-run: sudo /opt/vyatta/bin/sudo-users/vyatta-show-vrrp.pl "$4" "$6"
+allowed: sudo /opt/vyatta/bin/sudo-users/vyatta-show-vrrp.pl --show=interface --intf="${COMP_WORDS[COMP_CWORD-2]}"
+run: sudo /opt/vyatta/bin/sudo-users/vyatta-show-vrrp.pl --show=detail --intf=$4 --vrid=$6
diff --git a/templates/show/vrrp/interface/node.tag/node.def b/templates/show/vrrp/interface/node.tag/node.def
index 1defd31..f9e53ee 100644
--- a/templates/show/vrrp/interface/node.tag/node.def
+++ b/templates/show/vrrp/interface/node.tag/node.def
@@ -1,3 +1,3 @@
help: Show VRRP information for specified interface
-allowed: /opt/vyatta/sbin/vyatta-keepalived.pl --vrrp-action=list-vrrp-intf
-run: sudo /opt/vyatta/bin/sudo-users/vyatta-show-vrrp.pl "$4"
+allowed: sudo /opt/vyatta/bin/sudo-users/vyatta-show-vrrp.pl --show=interface
+run: sudo /opt/vyatta/bin/sudo-users/vyatta-show-vrrp.pl --show=detail --intf=$4
diff --git a/templates/show/vrrp/node.def b/templates/show/vrrp/node.def
index 51e9b9d..606e215 100644
--- a/templates/show/vrrp/node.def
+++ b/templates/show/vrrp/node.def
@@ -1,2 +1,2 @@
help: Show Virtual Router Redundancy Protocol (VRRP) information
-run: sudo /opt/vyatta/bin/sudo-users/vyatta-show-vrrp.pl
+run: sudo /opt/vyatta/bin/sudo-users/vyatta-show-vrrp.pl --show=summary
diff --git a/templates/show/vrrp/statistics/interface/node.def b/templates/show/vrrp/statistics/interface/node.def
new file mode 100644
index 0000000..7d7d648
--- /dev/null
+++ b/templates/show/vrrp/statistics/interface/node.def
@@ -0,0 +1 @@
+help: Show VRRP statistics for specified interface
diff --git a/templates/show/vrrp/statistics/interface/node.tag/group/node.def b/templates/show/vrrp/statistics/interface/node.tag/group/node.def
new file mode 100644
index 0000000..4673669
--- /dev/null
+++ b/templates/show/vrrp/statistics/interface/node.tag/group/node.def
@@ -0,0 +1 @@
+help: Show VRRP statistics for specified interface and group
diff --git a/templates/show/vrrp/statistics/interface/node.tag/group/node.tag/node.def b/templates/show/vrrp/statistics/interface/node.tag/group/node.tag/node.def
new file mode 100644
index 0000000..05606f8
--- /dev/null
+++ b/templates/show/vrrp/statistics/interface/node.tag/group/node.tag/node.def
@@ -0,0 +1,3 @@
+help: Show VRRP statistics for specified interface and group
+allowed: sudo /opt/vyatta/bin/sudo-users/vyatta-show-vrrp.pl --show=interface --intf="${COMP_WORDS[COMP_CWORD-2]}"
+run: sudo /opt/vyatta/bin/sudo-users/vyatta-show-vrrp.pl --show=stats --intf=$5 --vrid=$7
diff --git a/templates/show/vrrp/statistics/interface/node.tag/node.def b/templates/show/vrrp/statistics/interface/node.tag/node.def
new file mode 100644
index 0000000..494032b
--- /dev/null
+++ b/templates/show/vrrp/statistics/interface/node.tag/node.def
@@ -0,0 +1,3 @@
+help: Show VRRP statistics for specified interface
+allowed: sudo /opt/vyatta/bin/sudo-users/vyatta-show-vrrp.pl --show=interface
+run: sudo /opt/vyatta/bin/sudo-users/vyatta-show-vrrp.pl --show=stats --intf=$5
diff --git a/templates/show/vrrp/statistics/node.def b/templates/show/vrrp/statistics/node.def
new file mode 100644
index 0000000..d125c2a
--- /dev/null
+++ b/templates/show/vrrp/statistics/node.def
@@ -0,0 +1,2 @@
+help: Show Virtual Router Redundancy Protocol (VRRP) statistics
+run: sudo /opt/vyatta/bin/sudo-users/vyatta-show-vrrp.pl --show=stats
diff --git a/templates/show/vrrp/sync-group/group/node.def b/templates/show/vrrp/sync-group/group/node.def
new file mode 100644
index 0000000..7d7d648
--- /dev/null
+++ b/templates/show/vrrp/sync-group/group/node.def
@@ -0,0 +1 @@
+help: Show VRRP statistics for specified interface
diff --git a/templates/show/vrrp/sync-group/group/node.tag/node.def b/templates/show/vrrp/sync-group/group/node.tag/node.def
new file mode 100644
index 0000000..8beb76e
--- /dev/null
+++ b/templates/show/vrrp/sync-group/group/node.tag/node.def
@@ -0,0 +1,3 @@
+help: Show VRRP statistics for specified interface
+allowed: sudo /opt/vyatta/bin/sudo-users/vyatta-show-vrrp.pl --show=syncs
+run: sudo /opt/vyatta/bin/sudo-users/vyatta-show-vrrp.pl --show=sync --intf=$5
diff --git a/templates/show/vrrp/sync-group/node.def b/templates/show/vrrp/sync-group/node.def
new file mode 100644
index 0000000..5242743
--- /dev/null
+++ b/templates/show/vrrp/sync-group/node.def
@@ -0,0 +1,3 @@
+help: Show VRRP sync-group information
+run: /opt/vyatta/bin/sudo-users/vyatta-show-vrrp.pl --show=sync
+