mirror of
https://github.com/xcat2/xcat-core.git
synced 2025-05-29 09:13:08 +00:00
511 lines
16 KiB
Perl
Executable File
511 lines
16 KiB
Perl
Executable File
#!/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 Net::Ping;
|
|
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,
|
|
'snmp' => \$::SNMP,
|
|
'accessvlan=s' => \$::PVID,
|
|
'allowvlan=s' => \$::VID,
|
|
'port=s' => \$::PORT,
|
|
'mode=s' => \$::MODE,
|
|
'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 Mellanox 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;
|
|
my $vlan;
|
|
my $port;
|
|
my $mode;
|
|
|
|
# set community string for switch
|
|
my $community = "public";
|
|
my @snmpcs = xCAT::TableUtils->get_site_attribute("snmpc");
|
|
my $tmp = $snmpcs[0];
|
|
if (defined($tmp)) { $community = $tmp }
|
|
|
|
# get master
|
|
my @masters = xCAT::TableUtils->get_site_attribute("master");
|
|
my $master = $masters[0];
|
|
|
|
if (($::IP) || ($::ALL)) {
|
|
config_ip();
|
|
}
|
|
|
|
if (($::NAME) || ($::ALL)) {
|
|
config_hostname();
|
|
}
|
|
|
|
if (($::SNMP) || ($::ALL)) {
|
|
config_snmp();
|
|
}
|
|
|
|
if (($::CONFIG) || ($::ALL)) {
|
|
run_rspconfig();
|
|
}
|
|
|
|
if ( ($::PVID) || ($::VID) ) {
|
|
config_vlan();
|
|
}
|
|
|
|
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) {
|
|
my $dip= $nodehash->{$switch}->[0]->{otherinterfaces};
|
|
if (!$dip) {
|
|
print "Add otherinterfaces attribute for discover ip: chdef $switch otherinterfaces=x.x.x.x\n";
|
|
next;
|
|
}
|
|
|
|
# Validate if this IP is reachable
|
|
my $p = Net::Ping->new();
|
|
if (!$p->ping($dip)) {
|
|
print "$dip is not reachable\n";
|
|
next;
|
|
}
|
|
|
|
my $static_ip= $nodehash->{$switch}->[0]->{ip};
|
|
|
|
# don't need to set if ip addresses are same
|
|
if ($dip eq $static_ip) {
|
|
print "static ip $static_ip and discovery ip $dip is same, will not process command for $switch\n";
|
|
next;
|
|
}
|
|
|
|
# get hostname
|
|
my $dswitch = xCAT::NetworkUtils->gethostname($dip);
|
|
|
|
# if hostnames are same, created different one for discovery name
|
|
if ($dswitch eq $switch) {
|
|
$dswitch="";
|
|
}
|
|
|
|
# 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 password=admin mgt=switch nodetype=switch";
|
|
$rc= xCAT::Utils->runcmd($cmd, 0);
|
|
$cmd = "makehosts $dswitch";
|
|
$rc= xCAT::Utils->runcmd($cmd, 0);
|
|
$cmd = "makedns $dswitch";
|
|
$rc= xCAT::Utils->runcmd($cmd, 0);
|
|
|
|
$cmd="rspconfig $dswitch sshcfg=enable";
|
|
$rc= xCAT::Utils->runcmd($cmd, 0);
|
|
if ($::RUNCMD_RC != 0) {
|
|
xCAT::MsgUtils->message("E"," Failed to config ssh passwordless for $dip");
|
|
print "Failed to config ssh passwordless for $dswitch, $dip\n";
|
|
push (@discover_switches, $dswitch);
|
|
next;
|
|
}
|
|
|
|
# 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 $dip");
|
|
print "$cmd failed, Couldn't communicate with $dswitch, $dip\n";
|
|
push (@discover_switches, $dswitch);
|
|
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);
|
|
|
|
if (!$p->ping($static_ip)) {
|
|
print "$switch: Failed to change ip address to $static_ip\n";
|
|
next;
|
|
}
|
|
|
|
push (@discover_switches, $dswitch);
|
|
push (@config_switches, $switch);
|
|
print "$switch: Changing IP address to static IP $static_ip\n";
|
|
}
|
|
|
|
if (@config_switches) {
|
|
# update switch status
|
|
my $csw = join(",",@config_switches);
|
|
$cmd = "chdef $csw status=ip_configed otherinterfaces=";
|
|
$rc= xCAT::Utils->runcmd($cmd, 0);
|
|
$cmd = "makehosts $csw";
|
|
$rc= xCAT::Utils->runcmd($cmd, 0);
|
|
}
|
|
|
|
if (@discover_switches) {
|
|
my $dsw = join(",",@discover_switches);
|
|
# remove discover switch from xCATdb and /etc/hosts
|
|
$cmd = "makedns -d $dsw";
|
|
$rc= xCAT::Utils->runcmd($cmd, 0);
|
|
$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']);
|
|
|
|
# get the site domain value
|
|
my @domains = xCAT::TableUtils->get_site_attribute("domain");
|
|
my $sitedomain = $domains[0];
|
|
|
|
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 = "makehosts $switch";
|
|
$rc= xCAT::Utils->runcmd($cmd, 0);
|
|
|
|
$cmd="xdsh $switch -l $user --devicetype IBSwitch::Mellanox 'enable;configure terminal;hostname $switch;ip name-server $master;ip domain-list $sitedomain;ip default-gateway $master;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);
|
|
print "$switch: Changing host name to $switch\n";
|
|
}
|
|
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_auth;
|
|
my $snmp_version;
|
|
my $cmd;
|
|
|
|
my $switchtab = xCAT::Table->new('switches');
|
|
my $switchhash = $switchtab->getNodesAttribs(\@nodes,['snmpversion','sshusername','sshpassword','username','password','auth','privacy']);
|
|
foreach my $switch (@nodes)
|
|
{
|
|
#enable snmp function on the switch
|
|
$cmd=`rspconfig $switch snmpcfg=enable`;
|
|
|
|
my $user = $switchhash->{$switch}->[0]->{sshusername};
|
|
if (!$user) {
|
|
print "switch ssh username is not defined, use default one\n";
|
|
$user="admin";
|
|
}
|
|
$snmp_version = $switchhash->{$switch}->[0]->{snmpversion};
|
|
$snmp_passwd = $switchhash->{$switch}->[0]->{password};
|
|
|
|
#config snmpv1 with community string defined in the switches table
|
|
unless ($snmp_version =~ /3/) {
|
|
if ($snmp_passwd) {
|
|
$cmd=`rspconfig $switch community=$snmp_passwd`;
|
|
print "config snmp community string $snmp_passwd\n";
|
|
next;
|
|
}
|
|
}
|
|
|
|
#config snmpv3 defined in the switches table
|
|
$snmp_user = $switchhash->{$switch}->[0]->{username};
|
|
if (!$snmp_user) {
|
|
print "No snmp user defined for switch $switch. Will not configure snmpv3\n";
|
|
next;
|
|
}
|
|
$snmp_auth = $switchhash->{$switch}->[0]->{auth};
|
|
my $snmp_privacy = $switchhash->{$switch}->[0]->{privacy};
|
|
|
|
my $cmd_prefix = "xdsh $switch -l $user --devicetype IBSwitch::Mellanox";
|
|
my $cmd;
|
|
# Build up the commands for easier readability
|
|
$cmd = $cmd . "enable\;";
|
|
$cmd = $cmd . "configure terminal\;";
|
|
$cmd = $cmd . "snmp-server user $snmp_user v3 enable\;";
|
|
if ($snmp_privacy) {
|
|
$cmd = $cmd . "snmp-server user $snmp_user v3 auth $snmp_auth $snmp_passwd priv $snmp_privacy $snmp_passwd\;";
|
|
} else {
|
|
$cmd = $cmd . "snmp-server user $snmp_user v3 auth $snmp_auth $snmp_passwd\; no snmp-server user $snmp_user v3 require-privacy\;";
|
|
}
|
|
|
|
print "$switch: snmpv3 configured\n";
|
|
|
|
$cmd = $cmd . "configuration write\;exit\;";
|
|
my $final_cmd = $cmd_prefix . " \"" . $cmd . "\"";
|
|
|
|
`$final_cmd`
|
|
}
|
|
}
|
|
|
|
sub run_rspconfig {
|
|
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};
|
|
|
|
# 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' ";
|
|
$rc= xCAT::Utils->runcmd($cmd, 0);
|
|
|
|
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);
|
|
}
|
|
|
|
}
|
|
|
|
sub config_vlan {
|
|
my @ports;
|
|
my $port_input;
|
|
# checking for port number, switches is checked earlier
|
|
if ($::PORT) {
|
|
$port_input = $::PORT;
|
|
foreach my $num_str (split /,/, $port_input) {
|
|
if ($num_str =~ /-/) {
|
|
my ($min, $max) = split (/-/,$num_str);
|
|
while ($min <= $max) {
|
|
push (@ports,$min);
|
|
$min++;
|
|
}
|
|
} else {
|
|
push (@ports,$num_str);
|
|
}
|
|
}
|
|
} else {
|
|
xCAT::MsgUtils->message("E"," When configuring VLAN, a port must be provided.");
|
|
&usage;
|
|
exit(1);
|
|
}
|
|
|
|
my $access_vlan = $::PVID;
|
|
my $allowed_vlan = $::VID;
|
|
|
|
# will default to trunk mode
|
|
if ($::MODE) {
|
|
$mode = $::MODE;
|
|
if (!($mode =~ m/(access|trunk|hybrid|access-dcb|dot1q-tunnel)/) )
|
|
{
|
|
xCAT::MsgUtils->message("E"," Please provided supported mode");
|
|
&usage;
|
|
exit(1);
|
|
}
|
|
if ($mode =~ /hybrid/)
|
|
{
|
|
if (!$access_vlan) {
|
|
print "NOTE: Hybrid mode will change access VLAN back to 1\n";
|
|
print "If other than 1, run the command again with access VLAN number: \n";
|
|
print " configMellanox --switches switchnames --port port --accessvlan vlan1 --allowvlan vlan2 --mode mode\n";
|
|
$access_vlan = 1;
|
|
}
|
|
}
|
|
} else {
|
|
$mode = "access";
|
|
}
|
|
|
|
|
|
foreach my $switch (@nodes) {
|
|
my $devicetype;
|
|
|
|
# check if it is ethernet switch or ib switch
|
|
my $ccmd = "snmpwalk -Os -v1 -c $community $switch 1.3.6.1.2.1.1.1";
|
|
my $result = xCAT::Utils->runcmd($ccmd, 0);
|
|
|
|
# only supports MSX1410 and MSX1400 for Mellanox Ethernet switch now
|
|
if ( $result =~ /MSX14/ ) {
|
|
$devicetype = "EthSwitch::Mellanox";
|
|
}else {
|
|
xCAT::MsgUtils->message("E","Config IB switch VLAN is not support yet");
|
|
$devicetype = "IBSwitch::Mellanox";
|
|
next;
|
|
}
|
|
|
|
print "Tagging access VLAN to $access_vlan and allowed VLAN to $allowed_vlan with $mode mode for $switch port $port_input\n";
|
|
|
|
my $cmd_prefix = "xdsh $switch --devicetype $devicetype";
|
|
foreach my $port (@ports) {
|
|
my $cmd;
|
|
# Build up the commands for easier readability
|
|
$cmd = $cmd . "enable\;";
|
|
$cmd = $cmd . "configure terminal\;";
|
|
if ($access_vlan){
|
|
$cmd = $cmd . "vlan $access_vlan\;";
|
|
$cmd = $cmd . "exit\;";
|
|
}
|
|
if ($allowed_vlan){
|
|
$cmd = $cmd . "vlan $allowed_vlan\;";
|
|
$cmd = $cmd . "exit\;";
|
|
}
|
|
$cmd = $cmd . "interface ethernet 1/$port\;";
|
|
$cmd = $cmd . "switchport mode $mode\;";
|
|
if ($mode =~ /access/) {
|
|
$cmd = $cmd . "switchport access vlan $access_vlan\;";
|
|
} elsif ($mode =~ /hybrid/) {
|
|
$cmd = $cmd . "switchport $mode allowed-vlan $allowed_vlan\;";
|
|
$cmd = $cmd . "switchport access vlan $access_vlan\;";
|
|
} else {
|
|
$cmd = $cmd . "switchport $mode allowed-vlan $allowed_vlan\;";
|
|
}
|
|
$cmd = $cmd . "exit\;exit\;exit\;";
|
|
my $final_cmd = $cmd_prefix . " \"" . $cmd . "\"";
|
|
|
|
`$final_cmd`
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#---------------------------------------------------------
|
|
|
|
=head3 usage
|
|
|
|
Displays message for -h option
|
|
|
|
=cut
|
|
|
|
#---------------------------------------------------------
|
|
sub usage
|
|
{
|
|
print "Usage:
|
|
configMellanox -h│--help
|
|
configMellanox --switches switchnames --ip
|
|
configMellanox --switches switchnames --name
|
|
configMellanox --switches switchnames --snmp
|
|
|
|
To set the ip address, hostname, config snmp and run rspconfig command:
|
|
configMellanox --switches switchnames --all
|
|
|
|
To run rspconfig command:
|
|
configMellanox --switches switchnames --config
|
|
|
|
To configure VLAN on a specified port (Mellanox Ethernet switch ONLY):
|
|
configMellanox --switches switchnames --port port --accessvlan vlan1 --allowvlan vlan2 --mode mode
|
|
|
|
The following mode are supported for switchport:
|
|
* access Only untagged ingress Ethernet packets are allowed
|
|
* trunk Only tagged ingress Ethernet packets are allowed
|
|
* hybrid Both tagged and untagged ingress Ethernet packets are allowed
|
|
* access-dcb Only untagged ingress Ethernet packets are allowed. Egress packets will be priority tagged
|
|
* dot1q-tunnel Both tagged and untagged ingress Ethernet packets are allowed. Egress packets are tagged with a second VLAN (802.1Q) header
|
|
|
|
\n";
|
|
}
|
|
|
|
|