2007-10-26 22:44:33 +00:00
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT_plugin::hosts ;
2008-07-18 20:22:45 +00:00
use strict ;
use warnings ;
2007-10-26 22:44:33 +00:00
use xCAT::Table ;
2012-08-09 04:07:40 +00:00
use xCAT::TableUtils ;
2010-05-27 07:42:49 +00:00
use xCAT::NetworkUtils ;
2007-10-26 22:44:33 +00:00
use Data::Dumper ;
2008-07-02 15:22:30 +00:00
use File::Copy ;
2009-04-02 21:38:45 +00:00
use Getopt::Long ;
2010-02-19 15:00:51 +00:00
use Fcntl ':flock' ;
2009-04-02 21:38:45 +00:00
2012-12-03 20:23:33 +00:00
my @ hosts ; #Hold /etc/hosts data to be written back
2009-04-02 21:38:45 +00:00
my $ LONGNAME ;
2010-01-07 19:33:58 +00:00
my $ OTHERNAMESFIRST ;
2010-01-11 18:36:24 +00:00
my $ ADDNAMES ;
2010-05-27 07:42:49 +00:00
my $ MACTOLINKLOCAL ;
2007-10-26 22:44:33 +00:00
2012-12-07 16:18:23 +00:00
############# TODO - add return code checking !!!!!
2012-12-03 20:23:33 +00:00
my % usage =
( makehosts = >
"Usage: makehosts <noderange> [-d] [-n] [-l] [-a] [-o] [-m]\n makehosts -h" ,
) ;
2007-10-26 22:44:33 +00:00
2012-12-03 20:23:33 +00:00
sub handled_commands
{
return { makehosts = > "hosts" , } ;
2007-10-26 22:44:33 +00:00
}
2012-12-03 20:23:33 +00:00
sub delnode
{
my $ node = shift ;
my $ ip = shift ;
unless ( $ node and $ ip )
{
return ;
} #bail if requested to do something that could zap /etc/hosts badly
my $ othernames = shift ;
my $ domain = shift ;
my $ idx = 0 ;
while ( $ idx <= $# hosts )
{
if ( ( $ ip and $ hosts [ $ idx ] =~ /^${ip}\s/ )
or $ hosts [ $ idx ] =~ /^\d+\.\d+\.\d+\.\d+\s+${node}[\s\.r]/ )
{
$ hosts [ $ idx ] = "" ;
}
$ idx + + ;
2010-02-11 21:01:24 +00:00
}
}
2012-12-03 20:23:33 +00:00
sub addnode
{
my $ node = shift ;
my $ ip = shift ;
unless ( $ node and $ ip )
{
return ;
} #bail if requested to do something that could zap /etc/hosts badly
my $ othernames = shift ;
my $ domain = shift ;
2012-12-07 16:18:23 +00:00
my $ nics = shift ;
2012-12-03 20:23:33 +00:00
my $ idx = 0 ;
my $ foundone = 0 ;
2012-12-07 16:18:23 +00:00
# if this ip was already added then just see if the entry
2012-12-03 20:23:33 +00:00
while ( $ idx <= $# hosts )
{
2012-12-07 16:18:23 +00:00
2012-12-03 20:23:33 +00:00
if ( $ hosts [ $ idx ] =~ /^${ip}\s/
or $ hosts [ $ idx ] =~ /^\d+\.\d+\.\d+\.\d+\s+${node}[\s\.r]/ )
{
if ( $ foundone )
{
$ hosts [ $ idx ] = "" ;
}
else
{
2012-12-07 16:18:23 +00:00
# we found a matching entry in the hosts list
if ( $ nics ) {
# we're processing the nics table and we found an
# existing entry for this ip so just add this
# node name as an alias for the existing entry
my ( $ hip , $ hnode , $ hdom , $ hother ) = split ( / / , $ hosts [ $ idx ] ) ;
# at this point "othernames", if any is just a space
# delimited list - so just add the node name to the list
$ othernames . = " $node" ;
$ hosts [ $ idx ] = build_line ( $ ip , $ hnode , $ domain , $ othernames ) ;
} else {
# otherwise just try to completely update the existing
# entry
$ hosts [ $ idx ] = build_line ( $ ip , $ node , $ domain , $ othernames ) ;
}
2012-12-03 20:23:33 +00:00
}
$ foundone = 1 ;
}
$ idx + + ;
2007-10-26 22:44:33 +00:00
}
2012-12-03 20:23:33 +00:00
if ( $ foundone ) { return ; }
2009-04-02 21:38:45 +00:00
2012-12-03 20:23:33 +00:00
my $ line = build_line ( $ ip , $ node , $ domain , $ othernames ) ;
push @ hosts , $ line ;
2009-04-02 21:38:45 +00:00
}
2012-12-03 20:23:33 +00:00
sub build_line
{
my $ ip = shift ;
my $ node = shift ;
my $ domain = shift ;
my $ othernames = shift ;
my @ o_names = ( ) ;
my @ n_names = ( ) ;
if ( defined $ othernames )
{
2012-12-07 16:18:23 +00:00
# the "hostnames" attribute can be a list delimited by
# either a comma or a space
2012-12-03 20:23:33 +00:00
@ o_names = split ( /,| / , $ othernames ) ;
2009-04-27 03:06:42 +00:00
}
2009-04-02 21:38:45 +00:00
my $ longname ;
2012-12-03 20:23:33 +00:00
foreach ( @ o_names )
{
if ( ( $ _ eq $ node ) || ( $ domain && ( $ _ eq "$node.$domain" ) ) )
{
$ longname = "$node.$domain" ;
$ _ = "" ;
}
elsif ( $ _ =~ /\./ )
{
if ( ! $ longname )
{
$ longname = $ _ ;
$ _ = "" ;
}
}
elsif ( $ ADDNAMES )
{
unshift ( @ n_names , "$_.$domain" ) ;
}
2010-01-11 18:43:18 +00:00
}
2012-12-03 20:23:33 +00:00
unshift ( @ o_names , @ n_names ) ;
2009-04-02 21:38:45 +00:00
2012-12-03 20:23:33 +00:00
if ( $ node =~ m/\.$domain$/i )
{
2009-07-14 15:55:31 +00:00
$ longname = $ node ;
$ node =~ s/\.$domain$// ;
2012-12-03 20:23:33 +00:00
}
elsif ( $ domain && ! $ longname )
{
$ longname = "$node.$domain" ;
}
2009-04-02 21:38:45 +00:00
2012-12-03 20:23:33 +00:00
$ othernames = join ( ' ' , @ o_names ) ;
if ( $ LONGNAME ) { return "$ip $longname $node $othernames\n" ; }
2010-01-11 19:06:16 +00:00
elsif ( $ OTHERNAMESFIRST ) { return "$ip $othernames $longname $node\n" ; }
2009-04-02 21:38:45 +00:00
else { return "$ip $node $longname $othernames\n" ; }
2007-10-26 22:44:33 +00:00
}
2009-04-02 21:38:45 +00:00
2012-12-03 20:23:33 +00:00
sub addotherinterfaces
{
my $ node = shift ;
my $ otherinterfaces = shift ;
my $ domain = shift ;
2009-04-02 21:38:45 +00:00
2012-12-03 20:23:33 +00:00
my @ itf_pairs = split ( /,/ , $ otherinterfaces ) ;
foreach ( @ itf_pairs )
{
2013-01-10 20:04:21 +00:00
my ( $ itf , $ ip ) ;
if ( $ _ =~ /!/ ) {
( $ itf , $ ip ) = split ( /!/ , $ _ ) ;
} else {
( $ itf , $ ip ) = split ( /:/ , $ _ ) ;
}
2012-12-03 20:23:33 +00:00
if ( $ ip && xCAT::NetworkUtils - > isIpaddr ( $ ip ) )
{
if ( $ itf =~ /^-/ )
{
$ itf = $ node . $ itf ;
}
addnode $ itf , $ ip , '' , $ domain ;
}
2009-07-06 20:39:39 +00:00
}
}
2012-12-03 20:23:33 +00:00
sub process_request
{
Getopt::Long:: Configure ( "bundling" ) ;
$ Getopt:: Long:: ignorecase = 0 ;
Getopt::Long:: Configure ( "no_pass_through" ) ;
my $ req = shift ;
my $ callback = shift ;
2012-12-07 16:18:23 +00:00
2012-12-03 20:23:33 +00:00
my $ HELP ;
my $ REMOVE ;
2009-07-06 20:39:39 +00:00
2012-12-03 20:23:33 +00:00
# parse the options
if ( $ req && $ req - > { arg } ) { @ ARGV = @ { $ req - > { arg } } ; }
else { @ ARGV = ( ) ; }
# print "argv=@ARGV\n";
if (
! GetOptions (
'h|help' = > \ $ HELP ,
'n' = > \ $ REMOVE ,
'd' = > \ $ ::DELNODE ,
'o|othernamesfirst' = > \ $ OTHERNAMESFIRST ,
'a|adddomaintohostnames' = > \ $ ADDNAMES ,
'm|mactolinklocal' = > \ $ MACTOLINKLOCAL ,
'l|longnamefirst' = > \ $ LONGNAME ,
)
)
{
$ callback - > ( { data = > $ usage { makehosts } } ) ;
return ;
2009-03-15 18:54:05 +00:00
}
2012-12-03 20:23:33 +00:00
# display the usage if -h
if ( $ HELP )
{
$ callback - > ( { data = > $ usage { makehosts } } ) ;
return ;
2007-10-26 22:44:33 +00:00
}
2012-12-03 20:23:33 +00:00
my $ hoststab = xCAT::Table - > new ( 'hosts' ) ;
my $ domain ;
my $ lockh ;
@ hosts = ( ) ;
if ( $ REMOVE )
{
if ( - e "/etc/hosts" )
{
my $ bakname = "/etc/hosts.xcatbak" ;
rename ( "/etc/hosts" , $ bakname ) ;
# add the localhost entry if trying to create the /etc/hosts from scratch
if ( $^O =~ /^aix/i )
{
push @ hosts , "127.0.0.1 loopback localhost\n" ;
}
else
{
push @ hosts , "127.0.0.1 localhost\n" ;
}
}
2008-06-03 20:28:01 +00:00
}
2012-12-03 20:23:33 +00:00
else
{
if ( - e "/etc/hosts" )
{
my $ bakname = "/etc/hosts.xcatbak" ;
copy ( "/etc/hosts" , $ bakname ) ;
}
2012-12-07 16:18:23 +00:00
# the contents of the /etc/hosts file is saved in the @hosts array
# the @hosts elements are updated and used to re-create the
# /etc/hosts file at the end by the writeout subroutine.
2012-12-03 20:23:33 +00:00
open ( $ lockh , ">" , "/tmp/xcat/hostsfile.lock" ) ;
flock ( $ lockh , LOCK_EX ) ;
my $ rconf ;
open ( $ rconf , "/etc/hosts" ) ; # Read file into memory
if ( $ rconf )
{
while ( <$rconf> )
{
push @ hosts , $ _ ;
}
close ( $ rconf ) ;
}
2007-10-26 22:44:33 +00:00
}
2012-12-03 20:23:33 +00:00
if ( $ req - > { node } )
{
if ( $ MACTOLINKLOCAL )
2010-05-27 07:42:49 +00:00
{
2012-12-03 20:23:33 +00:00
my $ mactab = xCAT::Table - > new ( "mac" ) ;
my $ machash = $ mactab - > getNodesAttribs ( $ req - > { node } , [ 'mac' ] ) ;
foreach my $ node ( keys % { $ machash } )
{
my $ mac = $ machash - > { $ node } - > [ 0 ] - > { mac } ;
if ( ! $ mac )
{
next ;
}
my $ linklocal = xCAT::NetworkUtils - > linklocaladdr ( $ mac ) ;
2012-12-07 16:18:23 +00:00
my $ netn ;
( $ domain , $ netn ) = & getIPdomain ( $ linklocal , $ callback ) ;
2012-12-03 20:23:33 +00:00
if ( $ ::DELNODE )
{
delnode $ node , $ linklocal , $ node , $ domain ;
}
else
{
addnode $ node , $ linklocal , $ node , $ domain ;
}
2010-05-27 07:42:49 +00:00
}
2010-02-11 21:01:24 +00:00
}
2012-12-03 20:23:33 +00:00
else
{
my $ hostscache =
$ hoststab - > getNodesAttribs ( $ req - > { node } ,
[ qw( ip node hostnames otherinterfaces ) ] ) ;
foreach ( @ { $ req - > { node } } )
{
my $ ref = $ hostscache - > { $ _ } - > [ 0 ] ;
2012-12-07 16:18:23 +00:00
my $ netn ;
( $ domain , $ netn ) = & getIPdomain ( $ ref - > { ip } , $ callback ) ;
2012-12-03 20:23:33 +00:00
if ( $ ::DELNODE )
{
delnode $ ref - > { node } , $ ref - > { ip } , $ ref - > { hostnames } , $ domain ;
}
else
{
if ( xCAT::NetworkUtils - > isIpaddr ( $ ref - > { ip } ) )
{
addnode $ ref - > { node } , $ ref - > { ip } , $ ref - > { hostnames } , $ domain ;
}
if ( defined ( $ ref - > { otherinterfaces } ) )
{
addotherinterfaces $ ref - > { node } , $ ref - > { otherinterfaces } , $ domain ;
}
}
} #end foreach
} # end else
# do the other node nics - if any
& donics ( $ req - > { node } , $ callback ) ;
}
else
{
if ( $ ::DELNODE )
{
return ;
2011-09-06 14:14:14 +00:00
}
2012-12-03 20:23:33 +00:00
my @ hostents =
$ hoststab - > getAllNodeAttribs (
[ 'ip' , 'node' , 'hostnames' , 'otherinterfaces' ] ) ;
my @ allnodes ;
foreach ( @ hostents )
{
push @ allnodes , $ _ - > { node } ;
2012-12-07 16:18:23 +00:00
my $ netn ;
( $ domain , $ netn ) = & getIPdomain ( $ _ - > { ip } ) ;
2012-12-03 20:23:33 +00:00
if ( xCAT::NetworkUtils - > isIpaddr ( $ _ - > { ip } ) )
{
addnode $ _ - > { node } , $ _ - > { ip } , $ _ - > { hostnames } , $ domain ;
}
if ( defined ( $ _ - > { otherinterfaces } ) )
{
addotherinterfaces $ _ - > { node } , $ _ - > { otherinterfaces } , $ domain ;
}
2011-05-18 01:31:14 +00:00
}
2012-12-03 20:23:33 +00:00
# also do nics table
& donics ( \ @ allnodes , $ callback ) ;
}
writeout ( ) ;
if ( $ lockh )
{
flock ( $ lockh , LOCK_UN ) ;
}
}
sub writeout
{
my $ targ ;
open ( $ targ , '>' , "/etc/hosts" ) ;
foreach ( @ hosts )
{
print $ targ $ _ ;
2007-10-26 22:44:33 +00:00
}
2012-12-03 20:23:33 +00:00
close ( $ targ ) ;
2007-10-26 22:44:33 +00:00
}
2012-12-03 20:23:33 +00:00
#-------------------------------------------------------------------------------
= head3 donics
Add the additional network interfaces for a list of nodes as
indicated in the nics table
Arguments:
node name
Returns:
0 - ok
1 - error
Globals:
Example:
my $ rc = & donics ( $ node , $ callback ) ;
Comments:
none
= cut
#-------------------------------------------------------------------------------
sub donics
{
my $ nodes = shift ;
my $ callback = shift ;
my @ nodelist = @ { $ nodes } ;
my $ nicstab = xCAT::Table - > new ( 'nics' ) ;
my $ nettab = xCAT::Table - > new ( 'networks' ) ;
foreach my $ node ( @ nodelist )
{
my % nichash ;
# get the nic info
my $ et =
$ nicstab - > getNodeAttribs (
$ node ,
[
'nicips' , 'nichostnamesuffixes' ,
'nicnetworks'
]
) ;
if (
! (
$ et - > { nicips }
&& $ et - > { 'nichostnamesuffixes' }
&& $ et - > { 'nicnetworks' }
)
)
{
next ;
}
2013-01-10 20:04:21 +00:00
# delimiter could be ":" or "!"
# old $et->{nicips} looks like "eth0:ip1,eth1:ip2,bmc:ip3..."
# OR new $et->{nicips} looks like "eth0!ip1,eth1!ip2,bmc!ip3..."
2012-12-03 20:23:33 +00:00
my @ nicandiplist = split ( ',' , $ et - > { 'nicips' } ) ;
foreach ( @ nicandiplist )
{
2013-01-10 20:04:21 +00:00
my ( $ nicname , $ nicip ) ;
# if it contains a "!" then split on "!"
if ( $ _ =~ /!/ ) {
( $ nicname , $ nicip ) = split ( '!' , $ _ ) ;
} else {
( $ nicname , $ nicip ) = split ( ':' , $ _ ) ;
}
2012-12-03 20:23:33 +00:00
$ nichash { $ nicname } { nicip } = $ nicip ;
}
my @ nicandsufx = split ( ',' , $ et - > { 'nichostnamesuffixes' } ) ;
foreach ( @ nicandsufx )
{
2013-01-10 20:04:21 +00:00
my ( $ nicname , $ nicsufx ) ;
if ( $ _ =~ /!/ ) {
( $ nicname , $ nicsufx ) = split ( '!' , $ _ ) ;
} else {
( $ nicname , $ nicsufx ) = split ( ':' , $ _ ) ;
}
2012-12-03 20:23:33 +00:00
$ nichash { $ nicname } { nicsufx } = $ nicsufx ;
}
my @ nicandnetwrk = split ( ',' , $ et - > { 'nicnetworks' } ) ;
foreach ( @ nicandnetwrk )
{
2013-01-10 20:04:21 +00:00
my ( $ nicname , $ netwrk ) ;
if ( $ _ =~ /!/ ) {
( $ nicname , $ netwrk ) = split ( '!' , $ _ ) ;
} else {
( $ nicname , $ netwrk ) = split ( ':' , $ _ ) ;
}
2012-12-03 20:23:33 +00:00
$ nichash { $ nicname } { netwrk } = $ netwrk ;
}
foreach my $ nic ( keys % nichash )
{
# make sure we have the short hostname
my $ shorthost ;
( $ shorthost = $ node ) =~ s/\..*$// ;
# construct hostname for nic
my $ nichostname = "$shorthost$nichash{$nic}{nicsufx}" ;
# get domain from network def
my $ nt = $ nettab - > getAttribs ( { netname = > "$nichash{$nic}{netwrk}" } , 'domain' ) ;
2012-12-07 16:18:23 +00:00
# look up the domain as a check or if it's not provided
my ( $ nicdomain , $ netn ) = & getIPdomain ( $ nichash { $ nic } { nicip } , $ callback ) ;
if ( $ nt - > { domain } ) {
if ( $ nichash { $ nic } { netwrk } ne $ netn ) {
my $ rsp ;
push @ { $ rsp - > { data } } , "The xCAT network name listed for \'$nichostname\' is \'$nichash{$nic}{netwrk}\' however the nic IP address \'$nichash{$nic}{nicip}\' seems to be in the \'$netn\' network.\nIf there is an error then makes corrections to the database definitions and re-run this command.\n" ;
xCAT::MsgUtils - > message ( "W" , $ rsp , $ callback ) ;
}
$ nicdomain = $ nt - > { domain } ;
}
2012-12-03 20:23:33 +00:00
if ( $ ::DELNODE )
{
2012-12-07 16:18:23 +00:00
delnode $ nichostname , $ nichash { $ nic } { nicip } , '' , $ nicdomain ;
2012-12-03 20:23:33 +00:00
}
else
{
2012-12-07 16:18:23 +00:00
addnode $ nichostname , $ nichash { $ nic } { nicip } , '' , $ nicdomain , 1 ;
2012-12-03 20:23:33 +00:00
}
} # end for each nic
} # end for each node
$ nettab - > close ;
$ nicstab - > close ;
return 0 ;
}
#-------------------------------------------------------------------------------
= head3 getIPdomain
Find the xCAT network definition match the IP and then return the
domain value from that network def .
Arguments:
node IP
callback
Returns:
2012-12-07 16:18:23 +00:00
domain and netname - ok
2012-12-03 20:23:33 +00:00
1 - error
Globals:
Example:
my $ rc = & getIPdomain ( $ nodeIP , $ callback ) ;
Comments:
none
= cut
#-------------------------------------------------------------------------------
sub getIPdomain
{
my $ nodeIP = shift ;
my $ callback = shift ;
# get the network defs
my $ nettab = xCAT::Table - > new ( 'networks' ) ;
my @ nets = $ nettab - > getAllAttribs ( 'netname' , 'net' , 'mask' , 'domain' ) ;
# foreach network def
foreach my $ enet ( @ nets )
{
my $ NM = $ enet - > { 'mask' } ;
my $ net = $ enet - > { 'net' } ;
if ( xCAT::NetworkUtils - > ishostinsubnet ( $ nodeIP , $ NM , $ net ) )
{
2012-12-07 16:18:23 +00:00
return ( $ enet - > { 'domain' } , $ enet - > { 'netname' } ) ;
2012-12-03 20:23:33 +00:00
last ;
}
}
2007-10-26 22:44:33 +00:00
2012-12-03 20:23:33 +00:00
# could not find the network domain for this IP address
return 1 ;
2007-10-26 22:44:33 +00:00
}
1 ;