2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2025-08-21 10:40:24 +00:00

Merge pull request #1519 from cxhong/switch

Switch-based switch discovery for BNT and Mellanox
This commit is contained in:
zet809
2016-08-09 10:21:01 +08:00
committed by GitHub
3 changed files with 725 additions and 6 deletions

View File

@@ -14,11 +14,13 @@ use xCAT::NodeRange;
use xCAT::NetworkUtils;
use xCAT::Utils;
use xCAT::SvrUtils;
use xCAT::MacMap;
use xCAT::Table;
use XML::Simple;
no strict;
use Data::Dumper;
use Socket;
use Expect;
#global variables for this module
my %globalopt;
@@ -37,6 +39,7 @@ my %global_switch_type = (
cisco => "Cisco",
BNT => "BNT",
Blade => "BNT",
G8052 => "BNT",
Mellanox => "Mellanox",
mellanox => "Mellanox",
MLNX => "Mellanox",
@@ -153,14 +156,14 @@ sub parse_args {
# Process command-line flags
#############################################
if (!GetOptions( \%opt,
qw(h|help V|Verbose v|version x z w r n range=s s=s))) {
qw(h|help V|Verbose v|version x z w r n range=s s=s setup))) {
return( usage() );
}
#############################################
# Check for node range
#############################################
if ( scalar(@ARGV) eq 1 ) {
if ( scalar(@ARGV) == 1 ) {
my @nodes = xCAT::NodeRange::noderange( @ARGV );
if (nodesmissed) {
return (usage( "The following nodes are not defined in xCAT DB:\n " . join(',', nodesmissed)));
@@ -261,6 +264,14 @@ sub parse_args {
$globalopt{n} = 1;
}
#########################################################
# setup discover switch
#########################################################
if ( exists( $opt{setup} )) {
$globalopt{setup} = 1;
}
return;
}
@@ -445,10 +456,10 @@ sub process_request {
if (exists($result->{$key}->{vendor})) {
$vendor = $result->{$key}->{vendor};
}
if ($key != /nomac/) {
if ($key !~ /nomac/) {
$mac = $key;
}
my $msg = sprintf $format, $ip, $name, $vendor, $key;
my $msg = sprintf $format, $ip, $name, $vendor, $mac;
send_msg(\%request, 0, $msg);
}
}
@@ -460,6 +471,11 @@ sub process_request {
xCATdB($result, \%request, $sub_req);
}
if (exists($globalopt{setup})) {
switchsetup($result, \%request, $sub_req);
}
return;
}
@@ -1117,14 +1133,14 @@ sub get_hostname {
#--------------------------------------------------------------------------------
sub get_switchtype {
my $vendor = shift;
my $key;
my $key = "Not support";
my $search_string = join '|', keys(%global_switch_type);
if ($vendor =~ /($search_string)/) {
$key = $1;
return $global_switch_type{$key};
} else {
return $vendor;
return $key;
}
}
@@ -1328,5 +1344,79 @@ sub format_xml {
return ($xml);
}
#--------------------------------------------------------------------------------
=head3 switchsetup
find discovered switches with predefine switches
for each discovered switches:
1) matching mac to a predefined node
2) if get predefined node, config the discovered switch, if failed, update
'otherinterface' attribute of predefined node
3) remove hosts record and node definition for the discovered switch
Arguments:
outhash: a hash containing the switches discovered
Returns:
result:
=cut
#--------------------------------------------------------------------------------
sub switchsetup {
my $outhash = shift;
my $request = shift;
my $sub_req = shift;
my @switchnode = ();
my $static_ip;
my $discover_switch;
my $nodes_to_config;
#print Dumper($outhash);
my $macmap = xCAT::MacMap->new();
#################################################
# call find_mac to match pre-defined switch and
# discovery switch
##################################################
foreach my $mac ( keys %$outhash ) {
my $ip = $outhash->{$mac}->{ip};
my $vendor = $outhash->{$mac}->{vendor};
# issue makehosts so we can use xdsh
my $dswitch = get_hostname($outhash->{$mac}->{name}, $ip);
my $node = $macmap->find_mac($mac,0);
if (!$node) {
send_msg($request, 0, "NO predefined switch matched this switch $dswitch with ip address $ip and mac address $mac");
next;
}
# get predefine node ip address
$static_ip = xCAT::NetworkUtils->getipaddr($node);
my $stype = get_switchtype($vendor);
if (exists($globalopt{verbose})) {
send_msg($request, 0, "Found Discovery switch $dswitch, $ip, $mac with predefine switch $node, $static_ip $stype switch\n" );
}
xCAT::Utils->runxcmd({ command => ['chdef'], arg => ['-t','node','-o',$node,"otherinterfaces=$ip",'status=Matched',"mac=$mac","switchtype=$stype","usercomment=$vendor"] }, $sub_req, 0, 1);
push (@{$nodes_to_config->{$stype}}, $node);
}
foreach my $mytype (keys %$nodes_to_config) {
my $config_script = "$::XCATROOT/shart/xcat/tools/config".$mytype;
if (-r -x $config_script) {
my $switches = join(",",@{${nodes_to_config}->{$mytype}});
send_msg($request, 0, "call to config $mytype switches $switches\n");
my $out = `$config_script --switches $switches --all`;
send_msg($request, 0, "output = $out\n");
} else {
send_msg($request, 0, "the switch type $mytype is not support yet\n");
}
}
return;
}
1;

View File

@@ -0,0 +1,371 @@
#!/usr/bin/env perl
#---------------------------------------------------------
# Configure Ethnet BNT switches
#---------------------------------------------------------
BEGIN
{
$::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
$::XCATDIR = $ENV{'XCATDIR'} ? $ENV{'XCATDIR'} : '/etc/xcat';
}
use lib "$::XCATROOT/lib/perl";
use strict;
use Socket;
use Getopt::Long;
use Expect;
use xCAT::Usage;
use xCAT::NodeRange;
use xCAT::NetworkUtils;
use xCAT::Utils;
use xCAT::Table;
use xCAT::MsgUtils;
Getopt::Long::Configure("bundling");
$Getopt::Long::ignorecase = 0;
#global variables
my @nodes;
my @filternodes;
#---------------------------------------------------------
#Main
# parse the options
if (
!GetOptions(
'h|help' => \$::HELP,
'switches=s' => \$::SWITCH,
'port=s' => \$::PORT,
'vlan=s' => \$::VLAN,
'user=s' => \$::USER,
'password=s' => \$::PASSWORD,
'group=s' => \$::GROUP,
'snmp' => \$::SNMP,
'ip' => \$::IP,
'name' => \$::NAME,
'all' => \$::ALL,
)
)
{
&usage;
exit(1);
}
# display the usage if -h or --help is specified
if ($::HELP)
{
&usage;
exit(0);
}
if ($::SWITCH) {
my @filternodes = xCAT::NodeRange::noderange( $::SWITCH );
if (nodesmissed) {
my $nodenotdefined = join(',', nodesmissed);
xCAT::MsgUtils->message("I","The following nodes are not defined in xCAT DB: $nodenotdefined");
}
# check switch type
my $switchestab = xCAT::Table->new('switches');
my $switches_hash = $switchestab->getNodesAttribs(\@filternodes,['switchtype']);
foreach my $fsw (@filternodes) {
if (($switches_hash->{$fsw}->[0]->{switchtype}) =~ /BNT/) {
push @nodes, $fsw;
} else {
xCAT::MsgUtils->message("E","The $fsw is not BNT switch, will not config");
}
}
unless (@nodes) {
xCAT::MsgUtils->message("E","No Valid Switch to process");
exit(1);
}
} else {
xCAT::MsgUtils->message("E","Invalid flag, please provide switches with --switches");
&usage;
exit(1);
}
my $switches = join(",",@nodes);
my $cmd;
my $vlan;
my $port;
my $sub_req;
my $rc;
if (($::IP) || ($::ALL))
{
config_ip();
}
if (($::NAME) || ($::ALL))
{
config_hostname();
}
if (($::SNMP) || ($::ALL))
{
config_snmp();
}
if ($::VLAN)
{
config_vlan();
}
sub config_ip {
my @config_switches;
my @discover_switches;
my $nodetab = xCAT::Table->new('hosts');
my $nodehash = $nodetab->getNodesAttribs(\@nodes,['ip','otherinterfaces']);
foreach my $switch (@nodes) {
print "change $switch to static ip address\n";
my $dip= $nodehash->{$switch}->[0]->{otherinterfaces};
my $static_ip= $nodehash->{$switch}->[0]->{ip};
#get hostname
my $dswitch = xCAT::NetworkUtils->gethostname($dip);
#if not defined, need to create one for xdsh to use
if (!$dswitch) {
my $ip_str = $dip;
$ip_str =~ s/\./\-/g;
$dswitch = "switch-$ip_str";
}
$cmd = "chdef -t node -o $dswitch groups=switch ip=$dip switchtype=BNT username=root password=admin protocol=telnet nodetype=switch";
$rc= xCAT::Utils->runcmd($cmd, 0);
$cmd = "makehosts $dswitch";
$rc= xCAT::Utils->runcmd($cmd, 0);
# verify if xdsh works
$cmd = "xdsh $dswitch --devicetype EthSwitch::BNT 'enable;configure terminal;exit' ";
$rc= xCAT::Utils->runcmd($cmd, 0);
if ($::RUNCMD_RC != 0) {
xCAT::MsgUtils->message("E","Couldn't communicate with $dswitch, $dip");
next;
}
$cmd="xdsh $dswitch -t 10 --devicetype EthSwitch::BNT 'enable;configure terminal;show interface ip;interface ip 1;ip address $static_ip;exit;exit' ";
$rc= xCAT::Utils->runcmd($cmd, 0);
print "finish setup static ip address for $switch\n";
push (@discover_switches, $dswitch);
push (@config_switches, $switch);
}
if (@config_switches) {
#update switch status
my $csw = join(",",@config_switches);
$cmd = "chdef $csw status=ip_configed otherinterfaces=";
$rc= xCAT::Utils->runcmd($cmd, 0);
}
if (@discover_switches) {
my $dsw = join(",",@discover_switches);
#remove discover switch from xCATdb and /etc/hosts
$cmd = "makehosts -d $dsw";
$rc= xCAT::Utils->runcmd($cmd, 0);
$cmd = "rmdef $dsw";
$rc= xCAT::Utils->runcmd($cmd, 0);
}
}
sub config_hostname {
my @config_switches;
my $switchtab = xCAT::Table->new('switches');
my $switchhash = $switchtab->getNodesAttribs(\@nodes,['sshusername','sshpassword']);
foreach my $switch (@nodes) {
my $user= $switchhash->{$switch}->[0]->{sshusername};
my $pwd= $switchhash->{$switch}->[0]->{sshpassword};
if ((!$user)||(!$pwd)) {
print "switch ssh username or password is not define, add default one\n";
$cmd = "chdef $switch username=root password=admin";
$rc= xCAT::Utils->runcmd($cmd, 0);
}
$cmd="xdsh $switch --devicetype EthSwitch::BNT 'enable;configure terminal;hostname $switch;write memory' ";
$rc= xCAT::Utils->runcmd($cmd, 0);
if ($::RUNCMD_RC != 0) {
xCAT::MsgUtils->message("E","Failed to setup hostname for $switch");
next;
}
push (@config_switches, $switch);
}
if (@config_switches) {
#update switch status
my $csw = join(",",@config_switches);
$cmd = "chdef $csw status=hostname_configed" ;
$rc= xCAT::Utils->runcmd($cmd, 0);
}
}
#setup secure SNMP v3
sub config_snmp {
my $snmp_user;
my $snmp_passwd;
my $snmp_group;
my @config_switches;
if ($::USER) {
$snmp_user = $::USER;
} else {
$snmp_user = "xcatadmin\r";
}
if ($::PASSWORD) {
$snmp_passwd = $::PASSWORD;
} else {
# Need a special character
$snmp_passwd = "xcatadminpassw0rd\@snmp\r";
}
if ($::GROUP) {
$snmp_group = $::GROUP;
} else {
$snmp_group = "xcatgroup\r";
}
foreach my $switch (@nodes) {
my $mysw;
my $enable_cmd="enable\r";
my $config_cmd="configure terminal\r";
my $exit_cmd="exit\r";
my $pwd_prompt = "password: ";
my $sw_prompt = "$switch>";
my $enable_prompt="$switch#";
my $config_prompt="^.*\\\(config\\\)\#";
$mysw = new Expect;
my $timeout = 20;
my $login_cmd = "telnet $switch\r";
my $passwd = "admin\r";
print "Setup SNMP server for $switch\n";
#create a SNMP user
my $cfg_user1="snmp-server user 5 name $snmp_user\r";
my $cfg_user2="snmp-server user 5 authentication-protocol sha authentication-password\r";
#create a SNMP group
my $cfg_group1="snmp-server group 5 group-name $snmp_group\r";
my $cfg_group2="snmp-server group 5 user-name $snmp_user\r";
my $cfg_group3="snmp-server group 5 security usm\r";
#Add access permission
my $cfg_access1="snmp-server access 5 name $snmp_group\r";
my $cfg_access2="snmp-server access 5 level authNoPriv\r";
my $cfg_access3="snmp-server access 5 security usm\r";
my $cfg_access4="snmp-server access 5 read-view iso\r";
$mysw->slave->stty(qw(sane -echo));
unless ($mysw->spawn($login_cmd))
{
$mysw->soft_close();
print "Unable to run $login_cmd\n";
next;
}
my @result = $mysw->expect(
$timeout,
[
$pwd_prompt,
sub {
$mysw->clear_accum();
$mysw->send("$passwd\r");
$mysw->clear_accum();
$mysw->exp_continue();
}
],
[
"-re", $sw_prompt,
sub {
$mysw->clear_accum();
$mysw->send($enable_cmd);
$mysw->exp_continue();
}
],
[
"-re", $enable_prompt,
sub {
$mysw->clear_accum();
$mysw->send($config_cmd);
$mysw->exp_continue();
}
],
[
"-re", $config_prompt,
sub {
$mysw->clear_accum();
$mysw->send($cfg_user1);
$mysw->send($cfg_user2);
$mysw->send($passwd);
$mysw->send($snmp_passwd);
$mysw->send($snmp_passwd);
sleep 1;
$mysw->clear_accum();
# create snmp group
$mysw->send($cfg_group1);
$mysw->send($cfg_group2);
$mysw->send($cfg_group3);
$mysw->clear_accum();
$mysw->send($cfg_access1);
$mysw->send($cfg_access2);
$mysw->send($cfg_access3);
$mysw->send($cfg_access4);
$mysw->clear_accum();
$mysw->send("write memory\r");
$mysw->send($exit_cmd);
$mysw->send($exit_cmd);
}
],
);
##########################################
# Expect error - report and quit
##########################################
if (defined($result[1]))
{
my $errmsg = $result[1];
$mysw->soft_close();
print "Failed expect command $errmsg\n";
exit(1);
}
$mysw->soft_close();
push (@config_switches, $switch);
}
if (@config_switches) {
#update switch status
my $csw = join(",",@config_switches);
$cmd = "chdef $csw status=switch_configed snmpversion=3 snmpauth=sha snmpusername=$snmp_user snmppassword=$snmp_passwd";
$rc= xCAT::Utils->runcmd($cmd, 0);
}
}
sub config_vlan {
if ($::PORT) {
$port = $::PORT;
} else {
&usage;
exit(1);
}
$vlan = $::VLAN;
print "Tagging VLAN=$vlan for $switches port $port\n";
#create vlan, tagged vlan
$cmd = `xdsh $switches --devicetype EthSwitch::BNT "enable;configure terminal;vlan $vlan;exit;interface port $port;switchport mode trunk;switchport trunk allowed vlan $vlan;write memory;exit;exit"`;
}
#---------------------------------------------------------
=head3 usage
Displays message for -h option
=cut
#---------------------------------------------------------
sub usage
{
print "Usage:
configBNT [-?│-h│--help]
configBNT [--switches switchnames] [--all]
configBNT [--switches switchnames] [--ip]
configBNT [--switches switchnames] [--name ]
configBNT [--switches switchnames] [--snmp] [--user snmp_user] [--password snmp_password] [--group snmp_group]
configBNT [--switches switchnames] [--port port] [--vlan vlan]
\n";
}

View File

@@ -0,0 +1,258 @@
#!/usr/bin/env perl
#---------------------------------------------------------
# Configure Ethnet Mellonax switches
#---------------------------------------------------------
BEGIN
{
$::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
$::XCATDIR = $ENV{'XCATDIR'} ? $ENV{'XCATDIR'} : '/etc/xcat';
}
use lib "$::XCATROOT/lib/perl";
use strict;
use Getopt::Long;
use Expect;
use xCAT::Usage;
use xCAT::NodeRange;
use xCAT::NetworkUtils;
use xCAT::Utils;
use xCAT::Table;
use xCAT::MsgUtils;
Getopt::Long::Configure("bundling");
$Getopt::Long::ignorecase = 0;
#global variables
my @nodes;
my @filternodes;
#---------------------------------------------------------
#Main
# parse the options
if (
!GetOptions(
'h|help' => \$::HELP,
'switches=s' => \$::SWITCH,
'config' => \$::CONFIG,
'ip' => \$::IP,
'name' => \$::NAME,
'all' => \$::ALL,
)
)
{
&usage;
exit(1);
}
# display the usage if -h or --help is specified
if ($::HELP)
{
&usage;
exit(0);
}
if ($::SWITCH)
{
my @filternodes = xCAT::NodeRange::noderange( $::SWITCH );
if (nodesmissed) {
my $nodenotdefined = join(',', nodesmissed);
xCAT::MsgUtils->message("I","The following nodes are not defined in xCAT DB: $nodenotdefined");
}
# check switch type
my $switchestab = xCAT::Table->new('switches');
my $switches_hash = $switchestab->getNodesAttribs(\@filternodes,['switchtype']);
foreach my $fsw (@filternodes) {
if (($switches_hash->{$fsw}->[0]->{switchtype}) =~ /Mellanox/) {
push @nodes, $fsw;
} else {
xCAT::MsgUtils->message("E","The $fsw is not BNT switch, will not config");
}
}
unless (@nodes) {
xCAT::MsgUtils->message("E","No Valid Switch to process");
exit(1);
}
} else {
xCAT::MsgUtils->message("E","Invalid flag, please provide switches with --switches");
&usage;
exit(1);
}
my $switches = join(",",@nodes);
my $user;
my $cmd;
my $rc;
my $master;
if (($::IP) || ($::ALL)) {
config_ip();
}
if (($::NAME) || ($::ALL)) {
config_hostname();
}
if (($::CONFIG) || ($::ALL)) {
run_rspconfig();
}
sub config_ip {
my @config_switches;
my @discover_switches;
# get host table for otherinterfaces
my $nodetab = xCAT::Table->new('hosts');
my $nodehash = $nodetab->getNodesAttribs(\@nodes,['ip','otherinterfaces']);
# get netmask from network table
my $nettab = xCAT::Table->new("networks");
my @nets;
if ($nettab) {
@nets = $nettab->getAllAttribs('net','mask');
}
foreach my $switch (@nodes) {
print "change $switch to static ip address\n";
my $dip= $nodehash->{$switch}->[0]->{otherinterfaces};
my $static_ip= $nodehash->{$switch}->[0]->{ip};
#get hostname
my $dswitch = xCAT::NetworkUtils->gethostname($dip);
print "dip=$dip, static=$static_ip, dsw=$dswitch\n";
#if not defined, need to create one for xdsh to use
if (!$dswitch) {
my $ip_str = $dip;
$ip_str =~ s/\./\-/g;
$dswitch = "switch-$ip_str";
}
$cmd = "chdef -t node -o $dswitch groups=switch ip=$dip switchtype=Mellanox username=admin nodetype=switch";
$rc= xCAT::Utils->runcmd($cmd, 0);
$cmd = "makehosts $dswitch";
$rc= xCAT::Utils->runcmd($cmd, 0);
# verify if xdsh works
$cmd = "xdsh $dswitch -l admin --devicetype IBSwitch::Mellanox 'enable;configure terminal;exit' ";
$rc= xCAT::Utils->runcmd($cmd, 0);
if ($::RUNCMD_RC != 0) {
xCAT::MsgUtils->message("E","Couldn't communicate with $dswitch, $dip");
next;
}
#get netmask
my $mask;
foreach my $net (@nets) {
if (xCAT::NetworkUtils::isInSameSubnet( $net->{'net'}, $static_ip, $net->{'mask'}, 0)) {
$mask=$net->{'mask'};
}
}
$cmd="xdsh $dswitch -t 10 -l admin --devicetype IBSwitch::Mellanox 'enable;configure terminal;no interface mgmt0 dhcp;interface mgmt0 ip address $static_ip $mask;configuration write;exit;exit' ";
$rc= xCAT::Utils->runcmd($cmd, 0);
push (@discover_switches, $dswitch);
push (@config_switches, $switch);
}
if (@config_switches) {
#update switch status
my $csw = join(",",@config_switches);
$cmd = "chdef $csw status=ip_configed otherinterfaces=";
$rc= xCAT::Utils->runcmd($cmd, 0);
}
if (@discover_switches) {
my $dsw = join(",",@discover_switches);
#remove discover switch from xCATdb and /etc/hosts
$cmd = "makehosts -d $dsw";
$rc= xCAT::Utils->runcmd($cmd, 0);
$cmd = "rmdef $dsw";
$rc= xCAT::Utils->runcmd($cmd, 0);
}
}
sub config_hostname {
my @config_switches;
my $switchtab = xCAT::Table->new('switches');
my $switchhash = $switchtab->getNodesAttribs(\@nodes,['sshusername']);
foreach my $switch (@nodes) {
my $user= $switchhash->{$switch}->[0]->{sshusername};
if (!$user) {
print "switch ssh username is not defined, add default one\n";
$cmd = "chdef $switch username=admin";
$rc= xCAT::Utils->runcmd($cmd, 0);
$user="admin";
}
$cmd="xdsh $switch -l $user --devicetype IBSwitch::Mellanox 'enable;configure terminal;hostname $switch;configuration write' ";
$rc= xCAT::Utils->runcmd($cmd, 0);
if ($::RUNCMD_RC != 0) {
xCAT::MsgUtils->message("E","Failed to setup hostname for $switch");
next;
}
push (@config_switches, $switch);
}
if (@config_switches) {
#update switch status
my $csw = join(",",@config_switches);
$cmd = "chdef $csw status=hostname_configed" ;
$rc= xCAT::Utils->runcmd($cmd, 0);
}
}
sub run_rspconfig {
my @config_switches;
my $switchtab = xCAT::Table->new('switches');
my $switchhash = $switchtab->getNodesAttribs(\@nodes,['sshusername']);
$master = `hostname -i`;
print "master=$master\n";
foreach my $switch (@nodes) {
my $user= $switchhash->{$switch}->[0]->{sshusername};
#call rspconfig command to setup switch
#enable ssh
$cmd=`rspconfig $switch sshcfg=enable`;
#enable snmp function on the switch
$cmd=`rspconfig $switch snmpcfg=enable`;
#enable the snmp trap
$cmd=`rspconfig $switch alert=enable`;
#Logging destination:
$cmd=`rspconfig $switch logdest=$master`;
#config ntp
$cmd = `xdsh $switch -l $user --devicetype IBSwitch::Mellanox "enable;configure terminal;ntp enable;ntpdate $master; ntp server $master;configuration write;show ntp" `;
push (@config_switches, $switch);
}
if (@config_switches) {
#update switch status
my $csw = join(",",@config_switches);
$cmd = "chdef $csw status=switch_configed" ;
$rc= xCAT::Utils->runcmd($cmd, 0);
}
}
#---------------------------------------------------------
=head3 usage
Displays message for -h option
=cut
#---------------------------------------------------------
sub usage
{
print "Usage:
configMellonax [-?│-h│--help]
configMellonax [--switches switchnames] [--all]
configMellonax [--switches switchnames] [--ip]
configMellonax [--switches switchnames] [--name]
configMellonax [--switches switchnames] [--config]
\n";
}