2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2025-05-29 09:13:08 +00:00
2020-02-02 14:40:24 -05:00

491 lines
14 KiB
Perl
Executable File

#!/usr/bin/env perl
#---------------------------------------------------------
# Configure cumulus/onie 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 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,
'port=s' => \$::PORT,
'vlan=s' => \$::VLAN,
'snmp' => \$::SNMP,
'ssh' => \$::SSH,
'license=s' => \$::LICENSE,
'ntp' => \$::NTP,
'all' => \$::ALL,
)
)
{
&usage;
exit(1);
}
# display the usage if -h or --help is specified
if ($::HELP)
{
&usage;
exit(0);
}
my $current_usr = getpwuid($>);
if ($current_usr ne "root")
{
print "Can't run this command for non-root user\n";
exit(1);
}
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}) =~ /onie/) {
push @nodes, $fsw;
} else {
xCAT::MsgUtils->message("E","The $fsw is not cumulus 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 (($::SSH) || ($::ALL))
{
config_ssh();
}
if ($::LICENSE)
{
install_license();
}
if ($::SNMP)
{
config_snmp();
}
if ($::NTP)
{
config_ntp();
}
if ($::VLAN)
{
#config_vlan();
}
sub config_ssh {
my $password = "CumulusLinux!";
my $userid = "cumulus";
my $timeout = 30;
my $keyfile = "/root/.ssh/id_rsa.pub";
my $rootkey = `cat /root/.ssh/id_rsa.pub`;
my $cmd;
my @config_switches;
# get netmask from network table
my $nettab = xCAT::Table->new("networks");
my @nets;
if ($nettab) {
@nets = $nettab->getAllAttribs('net','mask');
}
my $nodetab = xCAT::Table->new('hosts');
my $nodehash = $nodetab->getNodesAttribs(\@nodes,['ip','otherinterfaces']);
foreach my $switch (@nodes) {
my $static_ip = $nodehash->{$switch}->[0]->{ip};
my $discover_ip = $nodehash->{$switch}->[0]->{otherinterfaces};
my $ssh_ip;
my $p = Net::Ping->new();
if ($p->ping($static_ip)) {
$ssh_ip = $static_ip;
} elsif ($p->ping($discover_ip)) {
$ssh_ip = $discover_ip;
} else {
print "$switch is not reachable\n";
next;
}
#remove old host key from /root/.ssh/known_hosts
$cmd = `ssh-keygen -R $switch`;
$cmd = `ssh-keygen -R $ssh_ip`;
my ($exp, $errstr) = cumulus_connect($ssh_ip, $userid, $password, $timeout);
if (!defined $exp) {
print ("Failed to connect to $ssh_ip, $errstr\n");
next;
}
my $ret;
my $err;
($ret, $err) = cumulus_exec($exp, "mkdir -p /root/.ssh");
($ret, $err) = cumulus_exec($exp, "chmod 700 /root/.ssh");
($ret, $err) = cumulus_exec($exp, "echo \"$rootkey\" >/root/.ssh/authorized_keys");
($ret, $err) = cumulus_exec($exp, "chmod 644 /root/.ssh/authorized_keys");
#config dhcp ip address to static
if ($ssh_ip eq $discover_ip) {
#get netmask
my $mask;
foreach my $net (@nets) {
if (xCAT::NetworkUtils::isInSameSubnet( $net->{'net'}, $static_ip, $net->{'mask'}, 0)) {
$mask=$net->{'mask'};
last;
}
}
($ret, $err) = cumulus_exec($exp, "ifconfig eth0 $static_ip netmask $mask");
}
$exp->hard_close();
push (@config_switches, $switch);
}
if (@config_switches) {
#update switch status
my $csw = join(",",@config_switches);
$cmd = "chdef $csw status=ssh_configured otherinterfaces=";
$rc= xCAT::Utils->runcmd($cmd, 0);
print "ssh configured for $csw\n";
if ($::ALL) {
$cmd = "updatenode $csw -P hardeths,syslog,enablesnmp,configinterface";
$rc= xCAT::Utils->runcmd($cmd, 0);
if ($::RUNCMD_RC != 0) {
xCAT::MsgUtils->message("E","Failed to run updatenode, please check the switch");
print "Failed to run $cmd\n";
}
$cmd = "chdef $csw status=configured";
$rc= xCAT::Utils->runcmd($cmd, 0);
print "switch: $csw configured\n";
}
}
}
sub cumulus_connect {
my $server = shift;
my $userid = shift;
my $password = shift;
my $timeout = shift;
my $ssh = Expect->new;
my $command = 'ssh';
my @parameters = ($userid . "@" . $server);
$ssh->debug(0);
$ssh->log_stdout(0); # suppress stdout output..
unless ($ssh->spawn($command, @parameters))
{
my $err = $!;
$ssh->soft_close();
my $rsp;
return(undef, "unable to run command $command $err\n");
}
$ssh->expect($timeout,
[ "-re", qr/WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED/, sub {die "WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!\n"; } ],
[ "-re", qr/\(yes\/no\)\?\s*$/, sub { $ssh->send("yes\n"); exp_continue; } ],
[ "-re", qr/ password:/, sub {$ssh->send("$password\n"); exp_continue; } ],
[ "-re", qr/:~\$/, sub { $ssh->send("sudo su\n"); exp_continue; } ],
[ "-re", qr/ password for cumulus:/, sub { $ssh->send("$password\n"); exp_continue; } ],
[ "-re", qr/.*\/home\/cumulus#/, sub { $ssh->clear_accum(); } ],
[ timeout => sub { die "No login.\n"; } ]
);
$ssh->clear_accum();
return ($ssh);
}
sub cumulus_exec {
my $exp = shift;
my $cmd = shift;
my $timeout = shift;
my $prompt = shift;
$timeout = 10 unless defined $timeout;
$prompt = qr/.*\/home\/cumulus#/ unless defined $prompt;
$exp->clear_accum();
$exp->send("$cmd\n");
my ($mpos, $merr, $mstr, $mbmatch, $mamatch) = $exp->expect(6, "-re", $prompt);
if (defined $merr) {
return(undef,$merr);
}
return($mbmatch);
}
# for cumulus switch, need to set the license file
sub install_license {
my @config_switches;
print "install_license\n";
my $license_file = "/root/license.txt";
my $file_name = "/root/license.txt";
if ($::LICENSE) {
$license_file = $::LICENSE;
}
print "file = $license_file\n";
if (!(-e $license_file) ) {
print "license file $license_file does not exist\n";
return;
}
foreach my $switch (@nodes) {
my $cmd = "xdcp $switch $license_file $file_name";
$rc= xCAT::Utils->runcmd($cmd, 0);
if ($::RUNCMD_RC != 0) {
xCAT::MsgUtils->message("E","Failed to xscp $license_file to $switch");
print "$switch: Failed to run $cmd\n";
next;
}
$cmd = "xdsh $switch '/usr/cumulus/bin/cl-license -i $file_name' ";
$rc= xCAT::Utils->runcmd($cmd, 0);
if ($::RUNCMD_RC != 0) {
xCAT::MsgUtils->message("E","Failed to $cmd to $switch");
print "$switch: Failed to run $cmd\n";
next;
}
#restart switchd and reload interface
$cmd = "xdsh $switch 'systemctl enable switchd;systemctl restart switchd;ifreload -a' ";
xCAT::Utils->runcmd($cmd, 0);
push (@config_switches, $switch);
}
if (@config_switches) {
my $csw = join(",",@config_switches);
print "license is installed on $csw\n";
}
}
#get snmp attributes from switches tabele and setup secure SNMP v3
sub config_snmp {
my $switchestab = xCAT::Table->new('switches');
my $switches_hash = $switchestab->getNodesAttribs(\@nodes,['username','password','privacy','auth']);
foreach my $switch (@nodes) {
#check if xdsh works
$cmd = "xdsh $switch date";
$rc= xCAT::Utils->runcmd($cmd, 0);
if ($::RUNCMD_RC != 0) {
xCAT::MsgUtils->message("E","xdsh command to $switch failed");
print "$switch: Failed to run $cmd\n";
next;
}
my $username = $switches_hash->{$switch}->[0]->{username};
my $password = $switches_hash->{$switch}->[0]->{password};
my $auth = $switches_hash->{$switch}->[0]->{auth};
my $privacy = $switches_hash->{$switch}->[0]->{privacy};
my $privpwd;
if (defined $privacy) {
$privpwd = $password;
}
my $libconf = "/var/lib/snmp/snmpd.conf";
my $etcconf = "/etc/snmp/snmpd.conf";
my $cmd_prefix = "xdsh $switch ";
my $cmd;
$cmd = $cmd . "systemctl stop snmpd.service;";
$cmd = $cmd . "sed -i '/$username/d' $libconf;";
$cmd = $cmd . "sed -i '/$username/d' $etcconf;";
$cmd = $cmd . "echo 'createUser $username $auth $password $privacy $privpwd' >> $etcconf;";
$cmd = $cmd . "echo 'rwuser $username' >> $etcconf;";
$cmd = $cmd . "systemctl start snmpd.service;";
my $dshcmd = $cmd_prefix . " \"" . $cmd . "\"";
$rc= xCAT::Utils->runcmd($dshcmd, 0);
if ($::RUNCMD_RC != 0) {
xCAT::MsgUtils->message("E","Failed to update snmpd.conf for $switch");
print "$switch: Failed to update snmpd.conf\n";
next;
}
print "$switch: snmp service is configured\n";
}
}
sub config_ntp {
my @config_switches;
my $cmd;
my $master;
my $ntpservers;
my $timezone;
#get ntpserver, master and timezone from site table
my @entries = xCAT::TableUtils->get_site_attribute("master");
my $master = $entries[0];
@entries = xCAT::TableUtils->get_site_attribute("timezone");
$timezone = $entries[0];
@entries = xCAT::TableUtils->get_site_attribute("ntpservers");
my $t_entry = $entries[0];
if (defined($t_entry)) {
$ntpservers = $t_entry;
} else {
$ntpservers = $master;
}
my @servers = split(',', $ntpservers);
#use ntpserver from network table if available
my $nettab = xCAT::Table->new("networks");
my @nets;
if ($nettab) {
@nets = $nettab->getAllAttribs('net','mask','ntpservers');
}
my $file = "temp.txt";
open(FILE , ">$file")
or die "cannot open file $file\n";
print FILE "#This file is created by xCAT \n";
print FILE "driftfile /var/lib/ntp/drift\n";
print FILE "disable auth\n";
print FILE "restrict 127.0.0.1\n";
print FILE "interface listen eth0\n";
foreach my $switch (@nodes) {
#check if xdsh works
$cmd = "xdsh $switch date";
$rc= xCAT::Utils->runcmd($cmd, 0);
if ($::RUNCMD_RC != 0) {
xCAT::MsgUtils->message("E","xdsh command to $switch failed");
print "$switch: Failed to run $cmd\n";
next;
}
$cmd = "xdsh $switch 'echo $timezone >/etc/timezone;dpkg-reconfigure --frontend noninteractive tzdata' ";
$rc= xCAT::Utils->runcmd($cmd, 0);
if ($::RUNCMD_RC != 0) {
print "$switch: Failed to update ntp timezone\n";
xCAT::MsgUtils->message("E","Failed to update ntp timezone for $switch");
}
#use ntpserver from network table if available
my $ntpserver;
foreach my $net (@nets) {
if (xCAT::NetworkUtils::isInSameSubnet( $net->{'net'}, $switch, $net->{'mask'}, 0)) {
$ntpserver=$net->{'ntpservers'};
if (defined $ntpserver) {
if ($ntpserver =~ /xcatmaster/) {
@servers = $master;
} else {
@servers = split(',', $ntpserver);
}
}
last;
}
}
foreach my $server (@servers) {
`echo "server $server iburst" >> $file`;
}
$cmd = "xdcp $switch $file";
$rc= xCAT::Utils->runcmd($cmd, 0);
$cmd = "xdsh $switch 'cp /etc/ntp.conf /etc/ntp.conf.orig;cp $file /etc/ntp.conf;rm -fr $file;systemctl restart ntp;systemctl enable ntp' ";
$rc= xCAT::Utils->runcmd($cmd, 0);
if ($::RUNCMD_RC != 0) {
xCAT::MsgUtils->message("E","Failed to update ntp for $switch");
print "$switch: Failed to configure ntp service\n";
next;
}
push (@config_switches, $switch);
}
close FILE;
$cmd = `rm -rf $file`;
if (@config_switches) {
#update switch status
my $csw = join(",",@config_switches);
$cmd = "chdef $csw status=ntp_configured";
$rc= xCAT::Utils->runcmd($cmd, 0);
print "$csw: NTP service is configured\n";
}
}
#---------------------------------------------------------
=head3 usage
Displays message for -h option
=cut
#---------------------------------------------------------
sub usage
{
print "Usage:
configonie -h│--help
configonie --switches switchnames --ssh
configonie --switches switchnames --license filename
configonie --switches switchnames --snmp
configonie --switches switchnames --ntp
To setup ssh passwordless, change ip to static, enable snmp configuration and configure basic interface :
configonie --switches switchnames --all
\n";
}