You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
289 lines
8.7 KiB
289 lines
8.7 KiB
7 years ago
|
#!/usr/bin/perl
|
||
|
#
|
||
|
# Simple little program that takes the name of VM, parses its XML to find the 'vnetx' bridge links,
|
||
|
# determines which bridge they're connected to and then takes the interfaces down, waits a few seconds, and
|
||
|
# brings it back up. It cycles the interfaces connected to the BCN, then the SN and finally the IFN, always
|
||
|
# in that order.
|
||
|
#
|
||
|
# The goal of this program is to simplify testing the Striker and Anvil! node installer scripts when using
|
||
|
# KVM/qemu based VMs.
|
||
|
#
|
||
|
# Exit codes;
|
||
|
# 0 = Normal exit.
|
||
|
# 1 = Not run as root
|
||
|
# 2 = Server name not passed in
|
||
|
# 3 = Server not found
|
||
|
# 4 = Server not running
|
||
|
#
|
||
|
|
||
|
use strict;
|
||
|
use warnings;
|
||
|
|
||
|
$| = 1;
|
||
|
|
||
|
our $debug = 1;
|
||
|
my $server = defined $ARGV[0] ? $ARGV[0] : "";
|
||
|
if (not $server)
|
||
|
{
|
||
|
print "[ Error ] - Server name required. Usage: '$0 <server>'\n";
|
||
|
exit(2);
|
||
|
}
|
||
|
# Make sure we're running as 'root'
|
||
|
# $< == real UID, $> == effective UID
|
||
|
if (($< != 0) && ($> != 0))
|
||
|
{
|
||
|
# Not root
|
||
|
print "[ Error ] - This program requires root (or sudo) access.\n";
|
||
|
exit(1);
|
||
|
}
|
||
|
#print "Searching: [$server] for 'vnetX' interfaces...\n";
|
||
|
|
||
|
# We don't read switches, as the only allowed switch is the server's name.
|
||
|
check_server_running($server);
|
||
|
|
||
|
# If we're here, the server was found and running.
|
||
|
my $nics = get_nic_list($server);
|
||
|
|
||
|
# Now cycle the NICs.
|
||
|
cycle_nics($server, $nics);
|
||
|
|
||
|
exit(0);
|
||
|
|
||
|
|
||
|
#############################################################################################################
|
||
|
# Functions #
|
||
|
#############################################################################################################
|
||
|
|
||
|
# This does the work of cycling the NICs.
|
||
|
sub cycle_nics
|
||
|
{
|
||
|
my ($server, $nics) = @_;
|
||
|
print __LINE__."; [ Debug ] - server: [".$server."]\n" if $debug >= 2;
|
||
|
|
||
|
print "Cycling network cables on the server: [".$server."]...\n";
|
||
|
|
||
|
my $nics_processed = 1;
|
||
|
my $say_network = "";
|
||
|
foreach my $bridge_type ("bcn", "sn", "ifn")
|
||
|
{
|
||
|
print __LINE__."; [ Debug ] - bridge_type: [".$bridge_type."]\n" if $debug >= 2;
|
||
|
foreach my $network_number (sort {$a cmp $b} keys %{$nics->{$bridge_type}})
|
||
|
{
|
||
|
print __LINE__."; [ Debug ] - network_number: [".$network_number."]\n" if $debug >= 2;
|
||
|
foreach my $bridge_number (sort {$a cmp $b} keys %{$nics->{$bridge_type}{$network_number}})
|
||
|
{
|
||
|
if ($bridge_type eq "bcn")
|
||
|
{
|
||
|
$say_network = "Back-Chanel Network ".$network_number." - Bridge ".$bridge_number;
|
||
|
}
|
||
|
elsif ($bridge_type eq "sn")
|
||
|
{
|
||
|
$say_network = "Storage Network ".$network_number." - Bridge ".$bridge_number;
|
||
|
}
|
||
|
elsif ($bridge_type eq "ifn")
|
||
|
{
|
||
|
$say_network = "Internet-Facing Network ".$network_number." - Bridge ".$bridge_number;
|
||
|
}
|
||
|
|
||
|
print __LINE__."; [ Debug ] - bridge_number: [".$bridge_number."]\n" if $debug >= 2;
|
||
|
foreach my $this_vnet (sort {$a cmp $b} keys %{$nics->{$bridge_type}{$network_number}{$bridge_number}})
|
||
|
{
|
||
|
print __LINE__."; [ Debug ] - this_vnet: [".$this_vnet."]\n" if $debug >= 2;
|
||
|
|
||
|
my $this_mac = $nics->{$bridge_type}{$network_number}{$bridge_number}{$this_vnet};
|
||
|
print __LINE__."; [ Debug ] - nics->${bridge_type}::${network_number}::${bridge_number}::${this_vnet}: [".$nics->{$bridge_type}{$network_number}{$bridge_number}{$this_vnet}."]\n" if $debug >= 2;
|
||
|
|
||
|
# Down
|
||
|
print "Unplugging: [".$this_vnet."] from: [".$say_network."]";
|
||
|
my $shell_call = "virsh domif-setlink ".$server." ".$this_vnet." down";
|
||
|
print "\n".__LINE__."; [ Debug ] - shell_call: [".$shell_call."]\n" if $debug >= 2;
|
||
|
open (my $file_handle, $shell_call." 2>&1 |") or die "Failed to call: [$shell_call], error was: $!\n";
|
||
|
while(<$file_handle>)
|
||
|
{
|
||
|
chomp;
|
||
|
my $line = $_;
|
||
|
print __LINE__."; [ Debug ] - line: [".$line."]\n" if $debug >= 2;
|
||
|
}
|
||
|
close $file_handle;
|
||
|
|
||
|
for (1..3)
|
||
|
{
|
||
|
#print "- Sleeping briefly\n";
|
||
|
print ".";
|
||
|
sleep 1;
|
||
|
}
|
||
|
|
||
|
print " Reconnecting";
|
||
|
$shell_call = "virsh domif-setlink ".$server." ".$this_vnet." up";
|
||
|
print "\n".__LINE__."; [ Debug ] - shell_call: [".$shell_call."]\n" if $debug >= 2;
|
||
|
open ($file_handle, $shell_call." 2>&1 |") or die "Failed to call: [$shell_call], error was: $!\n";
|
||
|
while(<$file_handle>)
|
||
|
{
|
||
|
chomp;
|
||
|
my $line = $_;
|
||
|
print __LINE__."; [ Debug ] - line: [".$line."]\n" if $debug >= 2;
|
||
|
}
|
||
|
close $file_handle;
|
||
|
|
||
|
print __LINE__."; [ Debug ] - nics_processed: [".$nics_processed."], nics->count: [".$nics->{count}."]\n" if $debug >= 2;
|
||
|
if ($nics_processed < $nics->{count})
|
||
|
{
|
||
|
#print "- Sleeping briefly\n";
|
||
|
for(1..3)
|
||
|
{
|
||
|
print ".";
|
||
|
sleep 1;
|
||
|
}
|
||
|
print " Up\n";
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
print ". Up.\n";
|
||
|
}
|
||
|
$nics_processed++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
print "- Done.\n";
|
||
|
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
# This parses the server's XML definition and returns a hash reference of interfaces to cycle.
|
||
|
sub get_nic_list
|
||
|
{
|
||
|
my ($server) = @_;
|
||
|
|
||
|
my $nic_count = 0;
|
||
|
my $nics = {};
|
||
|
my $bridge_number = 0;
|
||
|
my $network_number = 0;
|
||
|
my $bridge_type = "";
|
||
|
my $this_vnet = "";
|
||
|
my $this_mac = "";
|
||
|
my $in_interface = 0;
|
||
|
my $shell_call = "virsh dumpxml ".$server;
|
||
|
print __LINE__."; [ Debug ] - shell_call: [".$shell_call."]\n" if $debug >= 2;
|
||
|
open (my $file_handle, $shell_call." 2>&1 |") or die "Failed to call: [$shell_call], error was: $!\n";
|
||
|
while(<$file_handle>)
|
||
|
{
|
||
|
chomp;
|
||
|
my $line = $_;
|
||
|
print __LINE__."; [ Debug ] - line: [".$line."]\n" if $debug >= 2;
|
||
|
|
||
|
if ($line =~ /<interface type='network'>/)
|
||
|
{
|
||
|
$in_interface = 1;
|
||
|
}
|
||
|
|
||
|
if ($in_interface)
|
||
|
{
|
||
|
print __LINE__."; [ Debug ] - line: [".$line."]\n" if $debug >= 2;
|
||
|
|
||
|
if (($line =~ /source network='(.*?)'/) or ($line =~ /bridge='(.*?)'/))
|
||
|
{
|
||
|
my $this_bridge = $1;
|
||
|
print __LINE__."; [ Debug ] - this_bridge: [".$this_bridge."]\n" if $debug >= 2;
|
||
|
|
||
|
($bridge_type, $network_number, $bridge_number) = ($this_bridge =~ /^(\D+)(\d+)_bridge(\d+)$/);
|
||
|
print __LINE__."; [ Debug ] - bridge_type: [".$bridge_type."], network_number: [".$network_number."], bridge_number: [".$bridge_number."]\n" if $debug >= 2;
|
||
|
}
|
||
|
if ($line =~ /target dev='(.*?)'/)
|
||
|
{
|
||
|
$this_vnet = $1;
|
||
|
print __LINE__."; [ Debug ] - this_vnet: [".$this_vnet."]\n" if $debug >= 2;
|
||
|
}
|
||
|
if ($line =~ /address='(.*?)'/)
|
||
|
{
|
||
|
$this_mac = $1;
|
||
|
print __LINE__."; [ Debug ] - this_mac: [".$this_mac."]\n" if $debug >= 2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ($line =~ /<\/interface>/)
|
||
|
{
|
||
|
# Record the details.
|
||
|
print __LINE__."; [ Debug ] - bridge_type: [".$bridge_type."], network_number: [".$network_number."], bridge_number: [".$bridge_number."], this_vnet: [".$this_vnet."], this_mac: [".$this_mac."]\n" if $debug >= 2;
|
||
|
|
||
|
$nics->{$bridge_type}{$network_number}{$bridge_number}{$this_vnet} = $this_mac;
|
||
|
$nic_count++;
|
||
|
print __LINE__."; [ Debug ] - nics->${bridge_type}::${network_number}::${bridge_number}::${this_vnet}: [".$nics->{$bridge_type}{$network_number}{$bridge_number}{$this_vnet}."]\n" if $debug >= 2;
|
||
|
|
||
|
# Clear the variables.
|
||
|
$in_interface = 0;
|
||
|
$bridge_number = 0;
|
||
|
$network_number = 0;
|
||
|
$bridge_type = "";
|
||
|
$this_vnet = "";
|
||
|
$this_mac = "";
|
||
|
}
|
||
|
}
|
||
|
close $file_handle;
|
||
|
|
||
|
$nics->{count} = $nic_count;
|
||
|
print __LINE__."; [ Debug ] - nics->count: [".$nics->{count}."]\n" if $debug >= 2;
|
||
|
|
||
|
return($nics);
|
||
|
}
|
||
|
|
||
|
# This checks to see if the name of the server was found and is running. It will exit if a problem is found.
|
||
|
sub check_server_running
|
||
|
{
|
||
|
my ($server) = @_;
|
||
|
|
||
|
my $found = 0;
|
||
|
my $shell_call = "virsh list --all";
|
||
|
print __LINE__."; [ Debug ] - shell_call: [".$shell_call."]\n" if $debug >= 2;
|
||
|
open (my $file_handle, $shell_call." 2>&1 |") or die "Failed to call: [$shell_call], error was: $!\n";
|
||
|
while(<$file_handle>)
|
||
|
{
|
||
|
chomp;
|
||
|
my $line = $_;
|
||
|
$line =~ s/\n$//;
|
||
|
$line =~ s/^\s+//;
|
||
|
$line =~ s/\s+$//;
|
||
|
$line =~ s/\s+/ /g;
|
||
|
print __LINE__."; [ Debug ] - line: [".$line."]\n" if $debug >= 2;
|
||
|
|
||
|
# Look for running servers
|
||
|
if ($line =~ /^(\d+) (.*?) (.*)$/)
|
||
|
{
|
||
|
my $id = $1;
|
||
|
my $this_server = $2;
|
||
|
my $state = $3;
|
||
|
print __LINE__."; [ Debug ] - id: [".$id."], server: [".$this_server."], state: [".$state."]\n" if $debug >= 2;
|
||
|
|
||
|
if ($server eq $this_server)
|
||
|
{
|
||
|
# Found it
|
||
|
$found = 1;
|
||
|
last;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# Look for stopped servers
|
||
|
if ($line =~ /^- (.*?) (.*)$/)
|
||
|
{
|
||
|
my $this_server = $1;
|
||
|
my $state = $2;
|
||
|
print __LINE__."; [ Debug ] - id: [-], server: [".$this_server."], state: [".$state."]\n" if $debug >= 2;
|
||
|
|
||
|
if ($server eq $this_server)
|
||
|
{
|
||
|
print "[ Error ] - The server: [".$server."] is not running.\n";
|
||
|
exit(4);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
close $file_handle;
|
||
|
|
||
|
if (not $found)
|
||
|
{
|
||
|
print "[ Error ] - The server: [".$server."] was not found.\n";
|
||
|
exit(3);
|
||
|
}
|
||
|
|
||
|
return(0);
|
||
|
}
|