xcat-core/xCAT-server/lib/xcat/plugins/bmcconfig.pm

182 lines
6.0 KiB
Perl
Raw Normal View History

# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT_plugin::bmcconfig;
use Data::Dumper;
use xCAT::Table;
use xCAT::MsgUtils;
use xCAT::Utils;
use xCAT::PasswordUtils;
use xCAT::IMMUtils;
use xCAT::TableUtils;
use IO::Select;
use Socket;
sub handled_commands {
return {
getbmcconfig => 'bmcconfig',
remoteimmsetup => 'bmcconfig',
};
}
sub genpassword {
my $length = shift;
my $password='';
my $characters= 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890';
srand; #have to reseed, rand is not rand otherwise
while (length($password) < $length) {
$password .= substr($characters,int(rand 63),1);
}
return $password;
}
sub net_parms {
my $ip = shift;
if (inet_aton($ip)) {
$ip = inet_ntoa(inet_aton($ip));
} else {
xCAT::MsgUtils->message("S","Unable to resolve $ip");
return undef;
}
my $nettab = xCAT::Table->new('networks');
unless ($nettab) { return undef };
my @nets = $nettab->getAllAttribs('net','mask','gateway');
foreach (@nets) {
my $net = $_->{'net'};
my $mask =$_->{'mask'};
my $gw = $_->{'gateway'};
$ip =~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/;
my $ipnum = ($1<<24)+($2<<16)+($3<<8)+$4;
$mask =~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/;
my $masknum = ($1<<24)+($2<<16)+($3<<8)+$4;
$net =~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/ or next; #next if ipv6, TODO: IPv6 support
my $netnum = ($1<<24)+($2<<16)+($3<<8)+$4;
if ($gw eq '<xcatmaster>') {
$gw=xCAT::NetworkUtils->my_ip_facing($ip);
}
if (($ipnum & $masknum)==$netnum) {
return ($ip,$mask,$gw);
}
}
xCAT::MsgUtils->message("S","xCAT BMC configuration error, no appropriate network for $ip found in networks, unable to determine netmask");
}
sub ok_with_node {
my $node = shift;
#Here we connect to the node on a privileged port (in the clear) and ask the
#node if it just asked us for credential. It's convoluted, but it is
#a convenient way to see if root on the ip has approved requests for
#credential retrieval. Given the nature of the situation, it is only ok
#to assent to such requests before users can log in. During postscripts
#stage in stateful nodes and during the rc scripts of stateless boot
my $select = new IO::Select;
#sleep 0.5; # gawk script race condition might exist, try to lose just in case
my $sock = new IO::Socket::INET(PeerAddr=>$node,
Proto => "tcp",
PeerPort => shift);
my $rsp;
unless ($sock) {return 0};
$select->add($sock);
print $sock "CREDOKBYYOU?\n";
unless ($select->can_read(5)) { #wait for data for up to five seconds
return 0;
}
my $response = <$sock>;
chomp($response);
if ($response eq "CREDOKBYME") {
return 1;
}
return 0;
}
sub process_request {
my $request = shift;
my $callback = shift;
my $node = $request->{'_xcat_clienthost'}->[0];
unless (ok_with_node($node,300)) {
$callback->({error=>["Unable to prove root on your IP approves of this request"],errorcode=>[1]});
return;
}
#my $sitetable = xCAT::Table->new('site');
my $ipmitable = xCAT::Table->new('ipmi');
my $tmphash;
my $username;
my $gennedpassword=0;
my $bmc;
my $password;
$tmphash=$ipmitable->getNodesAttribs([$node],['bmc','username','bmcport','password','taggedvlan']);
my $authmap = xCAT::PasswordUtils::getIPMIAuth(noderange=>[$node],ipmihash=>$tmphash);
if ($::XCATSITEVALS{genpasswords} eq "1" or $::XCATSITEVALS{genpasswords} =~ /y(es)?/i) {
$password = genpassword(10)."1cA!";
$gennedpassword=1;
} else {
$password = $authmap->{$node}->{password};
}
my $bmcport;
if (defined $tmphash->{$node}->[0]->{bmcport}) {
$bmcport = $tmphash->{$node}->[0]->{bmcport};
}
if ($tmphash->{$node}->[0]->{bmc} ) {
$bmc=$tmphash->{$node}->[0]->{bmc};
}
$username = $authmap->{$node}->{username};
my $cliusername;
if ($authmap->{$node}->{cliusername}) {
$cliusername = $authmap->{$node}->{cliusername};
} else {
$cliusername = $username;
}
my $clipassword;
if ($authmap->{$node}->{clipassword}) {
$clipassword = $authmap->{$node}->{clipassword};
} else {
$clipassword = $password;
}
unless (defined $bmc) {
xCAT::MsgUtils->message('S',"Unable to identify bmc for $node, refusing to give config data");
$callback->({error=>["Invalid table configuration for bmcconfig"],errorcode=>[1]});
return 1;
}
my $bmcport_counter=0;
foreach my $sbmc (split /,/,$bmc) {
(my $ip,my $mask,my $gw) = net_parms($sbmc);
unless ($ip and $mask and $username and $password) {
xCAT::MsgUtils->message('S',"Unable to determine IP, netmask, username, and/or pasword for $sbmc, ensure that host resolution is working. Best guess parameters would have been: IP: '$ip', netmask: '$mask', username: '$username', password: '$password'", );
$callback->({error=>["Invalid table configuration for bmcconfig"],errorcode=>[1]});
return 1;
}
if ($request->{command}->[0] eq 'remoteimmsetup') {
xCAT::IMMUtils::setupIMM($node,cliusername=>$cliusername,clipassword=>$clipassword,username=>$username,password=>$password,callback=>$callback);
return;
}
my $response={bmcip=>$ip,netmask=>$mask,gateway=>$gw,username=>$username,password=>$password};
if (defined $bmcport) {
if ($bmcport =~ /,/) {
my @sbmcport = (split /,/,$bmcport);
$response->{bmcport}=$sbmcport[$bmcport_counter];
} else {
$response->{bmcport}=$bmcport;
}
}
if (defined $tmphash->{$node}->[0]->{taggedvlan}) {
if ($tmphash->{$node}->[0]->{taggedvlan} =~ /,/) {
my @staggedvlan = (split /,/,$tmphash->{$node}->[0]->{taggedvlan});
$response->{taggedvlan}=$staggedvlan[$bmcport_counter];
} else {
$response->{taggedvlan}=$tmphash->{$node}->[0]->{taggedvlan};
}
}
$callback->($response);
$bmcport_counter += 1;
}
if ($gennedpassword) { # save generated password
$ipmitable->setNodeAttribs($node,{password=>$password});
}
return 1;
}
1;