2007-10-26 22:44:33 +00:00
#!/usr/bin/perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
2013-01-08 19:24:10 +00:00
use xCAT::TZUtils ;
use xCAT::WinUtils ;
2007-10-26 22:44:33 +00:00
package xCAT::Template ;
use strict ;
use xCAT::Table ;
use File::Basename ;
use File::Path ;
2011-04-11 13:51:09 +00:00
#use Data::Dumper;
2007-10-26 22:44:33 +00:00
use Sys::Syslog ;
2010-03-09 22:00:00 +00:00
use xCAT::ADUtils ; #to allow setting of one-time machine passwords
2012-08-09 04:00:45 +00:00
use xCAT::Utils ;
use xCAT::TableUtils ;
use xCAT::NetworkUtils ;
2014-04-11 09:40:34 +00:00
use XML::Simple ;
2012-04-01 03:17:14 +00:00
BEGIN
{
$ ::XCATROOT = $ ENV { 'XCATROOT' } ? $ ENV { 'XCATROOT' } : '/opt/xcat' ;
}
2010-03-09 22:00:00 +00:00
my $ netdnssupport = eval {
require Net::DNS ;
1 ;
} ;
2007-10-26 22:44:33 +00:00
2008-03-10 14:20:47 +00:00
my $ tmplerr ;
2007-10-26 22:44:33 +00:00
my $ table ;
my $ key ;
my $ field ;
my $ idir ;
my $ node ;
2010-03-09 22:00:00 +00:00
my % loggedrealms ;
2013-01-10 19:50:43 +00:00
my $ lastmachinepassdata ;
2013-01-10 20:30:44 +00:00
my $ localadminenabled ; #indicate whether Windows template has local logins enabled or not
2012-02-06 22:15:50 +00:00
my % tab_replacement = (
"noderes:nfsserver" = > "noderes:xcatmaster" ,
"noderes:tftpserver" = > "noderes:xcatmaster" ,
) ;
2007-10-26 22:44:33 +00:00
sub subvars {
my $ self = shift ;
my $ inf = shift ;
my $ outf = shift ;
2010-11-03 18:05:12 +00:00
$ tmplerr = undef ; #clear tmplerr since we are starting fresh
2007-10-26 22:44:33 +00:00
$ node = shift ;
2010-08-06 14:22:28 +00:00
my $ pkglistfile = shift ;
2011-06-27 03:46:29 +00:00
my $ media_dir = shift ;
2011-09-26 13:34:20 +00:00
my $ platform = shift ;
2012-06-25 12:03:03 +00:00
my $ partitionfile = shift ;
2011-09-30 18:07:03 +00:00
my % namedargs = @ _ ; #further expansion of this function will be named arguments, should have happened sooner.
unless ( $ namedargs { reusemachinepass } ) {
2013-01-10 19:50:43 +00:00
$ lastmachinepassdata - > { password } = "" ;
2011-09-30 18:07:03 +00:00
}
2010-08-06 14:22:28 +00:00
2007-10-26 22:44:33 +00:00
my $ outh ;
my $ inh ;
$ idir = dirname ( $ inf ) ;
open ( $ inh , "<" , $ inf ) ;
unless ( $ inh ) {
2008-03-10 14:20:47 +00:00
return "Unable to open $inf, aborting" ;
2007-10-26 22:44:33 +00:00
}
mkpath ( dirname ( $ outf ) ) ;
open ( $ outh , ">" , $ outf ) ;
unless ( $ outh ) {
2008-03-10 14:20:47 +00:00
return "Unable to open $outf for writing/creation, aborting" ;
2007-10-26 22:44:33 +00:00
}
my $ inc ;
#First load input into memory..
while ( <$inh> ) {
$ inc . = $ _ ;
}
close ( $ inh ) ;
my $ master ;
2012-05-18 06:14:35 +00:00
#my $sitetab = xCAT::Table->new('site');
2012-05-18 07:02:09 +00:00
my $ noderestab = xCAT::Table - > new ( 'noderes' ) ;
2012-05-18 06:14:35 +00:00
#(my $et) = $sitetab->getAttribs({key=>"master"},'value');
2012-08-09 04:00:45 +00:00
my @ masters = xCAT::TableUtils - > get_site_attribute ( "master" ) ;
2012-05-18 07:02:09 +00:00
my $ tmp = $ masters [ 0 ] ;
2012-05-18 06:14:35 +00:00
if ( defined ( $ tmp ) ) {
$ master = $ tmp ;
2007-10-26 22:44:33 +00:00
}
2012-08-09 04:00:45 +00:00
my $ ipfn = xCAT::NetworkUtils - > my_ip_facing ( $ node ) ;
2012-02-21 06:53:54 +00:00
if ( $ ipfn ) {
$ master = $ ipfn ;
}
2012-05-18 07:02:09 +00:00
my $ et = $ noderestab - > getNodeAttribs ( $ node , [ 'xcatmaster' ] ) ;
2007-10-26 22:44:33 +00:00
if ( $ et and $ et - > { 'xcatmaster' } ) {
$ master = $ et - > { 'xcatmaster' } ;
}
unless ( $ master ) {
die "Unable to identify master for $node" ;
}
$ ENV { XCATMASTER } = $ master ;
2009-05-11 20:46:03 +00:00
2012-09-14 02:58:34 +00:00
my @ nodestatus = xCAT::TableUtils - > get_site_attribute ( "nodestatus" ) ;
my $ tmp = $ nodestatus [ 0 ] ;
if ( defined ( $ tmp ) ) {
$ ENV { NODESTATUS } = $ tmp ;
}
2014-04-11 09:40:34 +00:00
2009-05-11 20:46:03 +00:00
#replace the env with the right value so that correct include files can be found
$ inc =~ s/#ENV:([^#]+)#/envvar($1)/eg ;
2010-08-06 14:22:28 +00:00
if ( $ pkglistfile ) {
#substitute the tag #INCLUDE_DEFAULT_PKGLIST# with package file name (for full install of rh, centos,SL, esx fedora)
$ inc =~ s/#INCLUDE_DEFAULT_PKGLIST#/#INCLUDE:$pkglistfile#/g ;
#substitute the tag #INCLUDE_DEFAULT_PKGLIST_S# with package file name (for full install of sles)
#substitute the tag #INCLUDE_DEFAULT_PERNLIST_S# with package file name (for full install sles
#substitute the tag #INCLUDE_DEFAULT_RMPKGLIST_S# with package file name (for full install sles)
$ inc =~ s/#INCLUDE_DEFAULT_PKGLIST_S#/#INCLUDE_PKGLIST:$pkglistfile#/g ;
$ inc =~ s/#INCLUDE_DEFAULT_PTRNLIST_S#/#INCLUDE_PTRNLIST:$pkglistfile#/g ;
$ inc =~ s/#INCLUDE_DEFAULT_RMPKGLIST_S#/#INCLUDE_RMPKGLIST:$pkglistfile#/g ;
}
2011-09-26 13:34:20 +00:00
if ( ( "ubuntu" eq $ platform ) || ( "debian" eq $ platform ) ) {
# since debian/ubuntu uses a preseed file instead of a kickstart file, pkglist
# must be included via simple string replacement instead of using includefile()
# the first line of $pkglistfile is the space-delimited package list
# the additional lines are considered preseed directives and included as is
if ( $ pkglistfile ) {
# handle empty and non-empty $pkglistfile's
if ( open PKGLISTFILE , "<$pkglistfile" ) {
2012-09-14 08:01:03 +00:00
my $ pkglist = '' ;
2011-09-26 13:34:20 +00:00
# append preseed directive lines
while ( <PKGLISTFILE> ) {
2012-09-14 08:01:03 +00:00
chomp $ _ ;
2013-03-14 08:50:57 +00:00
if ( /^\s*#.*/ ) {
next ;
}
2012-09-14 08:01:03 +00:00
$ pkglist . = " " . $ _ ;
2011-09-26 13:34:20 +00:00
}
2012-09-14 08:01:03 +00:00
$ inc =~ s/#INCLUDE_DEFAULT_PKGLIST_PRESEED#/$pkglist/g ;
2011-09-26 13:34:20 +00:00
close PKGLISTFILE ;
}
} else {
# handle no $pkglistfile
$ inc =~ s/#INCLUDE_DEFAULT_PKGLIST_PRESEED#//g ;
}
}
2010-08-06 14:22:28 +00:00
#do *all* includes, recursive and all
2007-10-26 22:44:33 +00:00
my $ doneincludes = 0 ;
while ( not $ doneincludes ) {
2014-06-12 13:04:39 +00:00
$ doneincludes = 1 ;
$ inc =~ s/#ENV:([^#]+)#/envvar($1)/eg ; # handle the variable in #INCLUDE
if ( $ inc =~ /#INCLUDE_PKGLIST:[^#^\n]+#/ ) {
$ doneincludes = 0 ;
$ inc =~ s/#INCLUDE_PKGLIST:([^#^\n]+)#/includefile($1, 0, 1)/eg ;
}
if ( $ inc =~ /#INCLUDE_PTRNLIST:[^#^\n]+#/ ) {
$ doneincludes = 0 ;
$ inc =~ s/#INCLUDE_PTRNLIST:([^#^\n]+)#/includefile($1, 0, 2)/eg ;
}
if ( $ inc =~ /#INCLUDE_RMPKGLIST:[^#^\n]+#/ ) {
$ doneincludes = 0 ;
$ inc =~ s/#INCLUDE_RMPKGLIST:([^#^\n]+)#/includefile($1, 0, 3)/eg ;
}
if ( $ inc =~ /#INCLUDE:[^#^\n]+#/ ) {
$ doneincludes = 0 ;
$ inc =~ s/#INCLUDE:([^#^\n]+)#/includefile($1, 0, 0)/eg ;
}
2014-06-10 12:03:22 +00:00
#support multiple paths of osimage in rh/sles diskfull installation
my @ pkgdirs ;
if ( defined ( $ media_dir ) ) {
@ pkgdirs = split ( "," , $ media_dir ) ;
my $ source ;
my $ source_in_pre ;
my $ c = 0 ;
foreach my $ pkgdir ( @ pkgdirs ) {
if ( $ platform =~ /^(rh|SL|centos|fedora)$/ ) {
if ( $ c == 0 ) {
# After some tests, if we put the repo in pre scripts in the kickstart like for rhels6.x
# the rhels5.9 will not be installed successfully. So put in kickstart directly.
$ source_in_pre . = "echo 'url --url http://'\$nextserver'/$pkgdir' >> /tmp/repos" ;
$ source . = "url --url http://#TABLE:noderes:\$NODE:nfsserver#/$pkgdir\n" ; #For rhels5.9
} else {
$ source_in_pre . = "\necho 'repo --name=pkg$c --baseurl=http://'\$nextserver'/$pkgdir' >> /tmp/repos" ;
$ source . = "repo --name=pkg$c --baseurl=http://#TABLE:noderes:\$NODE:nfsserver#/$pkgdir\n" ; #for rhels5.9
}
} elsif ( $ platform =~ /^(sles|suse)/ ) {
my $ http = "http://#TABLE:noderes:\$NODE:nfsserver#$pkgdir" ;
$ source . = " <listentry>
<media_url> $ http </media_url>
<product> SuSE - Linux - pkg $ c </product>
<product_dir> /</ product_dir >
< ask_on_error config:type = \ " boolean \ " > false </ask_on_error> < ! - - available since openSUSE 11.0 - - >
<name> SuSE - Linux - pkg $ c </name> < ! - - available since openSUSE 11.1 / SLES11 ( bnc #433981) -->
</listentry> " ;
$ source_in_pre . = "<listentry><media_url>http://'\$nextserver'$pkgdir</media_url><product>SuSE-Linux-pkg$c</product><product_dir>/</product_dir><ask_on_error config:type=\"boolean\">false</ask_on_error><name>SuSE-Linux-pkg$c</name></listentry>" ;
}
$ c + + ;
}
$ inc =~ s/#INSTALL_SOURCES#/$source/g ;
$ inc =~ s/#INSTALL_SOURCES_IN_PRE#/$source_in_pre/g ;
}
#ok, now do everything else..
my $ shortname = $ node ;
$ shortname =~ s/\..*// ;
$ inc =~ s/#TABLE:([^:]+):([^:]+):([^#]+)#/tabdb($1,$2,$3)/eg ;
$ inc =~ s/#TABLEBLANKOKAY:([^:]+):([^:]+):([^#]+)#/tabdb($1,$2,$3,'1')/eg ;
$ inc =~ s/#INCLUDE_NOP:([^#^\n]+)#/includefile($1,1,0)/eg ;
$ inc =~ s/#XCATVAR:([^#]+)#/envvar($1)/eg ;
$ inc =~ s/#ENV:([^#]+)#/envvar($1)/eg ;
$ inc =~ s/#MACHINEPASSWORD#/machinepassword()/eg ;
$ inc =~ s/#CRYPT:([^:]+):([^:]+):([^#]+)#/crydb($1,$2,$3)/eg ;
$ inc =~ s/#COMMAND:([^#]+)#/command($1)/eg ;
$ inc =~ s/#KICKSTARTNET#/kickstartnetwork()/eg ;
$ inc =~ s/#YAST2NET#/yast2network()/eg ;
$ inc =~ s/#ESXIPV6SETUP#/esxipv6setup()/eg ;
$ inc =~ s/#WINTIMEZONE#/xCAT::TZUtils::get_wintimezone()/eg ;
$ inc =~ s/#WINPRODKEY:([^#]+)#/get_win_prodkey($1)/eg ;
$ inc =~ s/#WINNETCFG#/windows_net_cfg()/eg ;
$ inc =~ s/#WINADJOIN#/windows_join_data()/eg ;
$ inc =~ s/#WINPOSTSCRIPTS#/windows_postscripts()/eg ;
$ inc =~ s/#WINDNSCFG#/windows_dns_cfg()/eg ;
$ inc =~ s/#WINACCOUNTDATA#/windows_account_data()/eg ;
$ inc =~ s/#WINDISABLENULLADMIN#/windows_disable_null_admin()/eg ;
$ inc =~ s/#MANAGEDADDRESSMODE#/managed_address_mode()/eg ;
$ inc =~ s/#HOSTNAME#/$node/g ;
$ inc =~ s/#SHORTNAME#/$shortname/g ;
$ inc =~ s/#GETNODEDOMAIN:([^#]+)#/get_node_domain($1)/eg ;
my $ nrtab = xCAT::Table - > new ( "noderes" ) ;
my $ tftpserver = $ nrtab - > getNodeAttribs ( $ node , [ 'tftpserver' ] ) ;
my $ sles_sdk_media = "http://" . $ tftpserver - > { tftpserver } . $ media_dir . "/sdk1" ;
$ inc =~ s/#SLES_SDK_MEDIA#/$sles_sdk_media/eg ;
#if user specify the partion file, replace the default partition strategy
if ( $ partitionfile ) {
#if the content of the partition file is definition replace the default is ok
my $ partcontent = '' ;
my $ scriptflag = 0 ;
if ( $ partitionfile =~ /^s:(.*)/ ) {
$ scriptflag = 1 ;
$ partitionfile = $ 1 ;
}
if ( - r $ partitionfile ) {
open ( $ inh , "<" , $ partitionfile ) ;
while ( <$inh> ) {
$ partcontent . = $ _ ;
}
close ( $ inh ) ;
2014-06-12 13:04:39 +00:00
2014-06-10 12:03:22 +00:00
#the content of the specified file is a script which can write partition definition into /tmp/partitionfile
if ( $ scriptflag ) {
#for redhat/sl/centos/kvm/fedora
if ( $ inc =~ /#XCAT_PARTITION_START#/ ) {
my $ tempstr = "%include /tmp/partitionfile\n" ;
$ inc =~ s/#XCAT_PARTITION_START#[\s\S]*#XCAT_PARTITION_END#/$tempstr/ ;
#modify the content in the file, and write into %pre part
#$partcontent = "cat > /tmp/partscript << EOFEOF\n" . $partcontent . "\nEOFEOF\n";
$ partcontent = "echo " . "'" . $ partcontent . "'" . ">/tmp/partscript\n" ;
$ partcontent . = "chmod 755 /tmp/partscript\n" ;
$ partcontent . = "/tmp/partscript\n" ;
#replace the #XCA_PARTITION_SCRIPT#
$ inc =~ s/#XCA_PARTITION_SCRIPT#/$partcontent/ ;
}
#for sles/suse
elsif ( $ inc =~ /<!-- XCAT-PARTITION-START -->/ ) {
my $ tempstr = "<drive><device>XCATPARTITIONTEMP</device></drive>" ;
$ inc =~ s/<!-- XCAT-PARTITION-START -->[\s\S]*<!-- XCAT-PARTITION-END -->/$tempstr/ ;
#$partcontent = "cat > /tmp/partscript << EOFEOF\n" . $partcontent . "\nEOFEOF\n";
$ partcontent = "echo " . "'" . $ partcontent . "'" . ">/tmp/partscript\n" ;
$ partcontent . = "chmod 755 /tmp/partscript\n" ;
$ partcontent . = "/tmp/partscript\n" ;
$ inc =~ s/#XCA_PARTITION_SCRIPT#/$partcontent/ ;
}
}
else {
$ partcontent =~ s/\s$// ;
if ( $ inc =~ /#XCAT_PARTITION_START#/ ) {
$ inc =~ s/#XCAT_PARTITION_START#[\s\S]*#XCAT_PARTITION_END#/$partcontent/ ;
}
elsif ( $ inc =~ /<!-- XCAT-PARTITION-START -->/ ) {
$ inc =~ s/<!-- XCAT-PARTITION-START -->[\s\S]*<!-- XCAT-PARTITION-END -->/$partcontent/ ;
}
2013-05-31 08:47:19 +00:00
}
2013-05-31 08:34:10 +00:00
}
}
2014-06-12 13:04:39 +00:00
$ inc =~ s/#ENV:([^#]+)#/envvar($1)/eg ; # handle the variable in #INCLUDE
2014-06-10 12:03:22 +00:00
if ( $ inc =~ /#INCLUDE_PKGLIST:[^#^\n]+#/ ) {
$ doneincludes = 0 ;
$ inc =~ s/#INCLUDE_PKGLIST:([^#^\n]+)#/includefile($1, 0, 1)/eg ;
}
if ( $ inc =~ /#INCLUDE_PTRNLIST:[^#^\n]+#/ ) {
$ doneincludes = 0 ;
$ inc =~ s/#INCLUDE_PTRNLIST:([^#^\n]+)#/includefile($1, 0, 2)/eg ;
}
if ( $ inc =~ /#INCLUDE_RMPKGLIST:[^#^\n]+#/ ) {
$ doneincludes = 0 ;
$ inc =~ s/#INCLUDE_RMPKGLIST:([^#^\n]+)#/includefile($1, 0, 3)/eg ;
}
if ( $ inc =~ /#INCLUDE:[^#^\n]+#/ ) {
$ doneincludes = 0 ;
$ inc =~ s/#INCLUDE:([^#^\n]+)#/includefile($1, 0, 0)/eg ;
}
2012-06-25 12:03:03 +00:00
}
2008-03-10 14:20:47 +00:00
if ( $ tmplerr ) {
2014-06-10 12:03:22 +00:00
close ( $ outh ) ;
return $ tmplerr ;
}
2007-10-26 22:44:33 +00:00
print $ outh $ inc ;
close ( $ outh ) ;
2008-03-10 14:20:47 +00:00
return 0 ;
2007-10-26 22:44:33 +00:00
}
2013-01-10 20:30:44 +00:00
sub windows_disable_null_admin {
#in the event where windows_account_data has not set an administrator user, we explicitly disable the administrator user
unless ( $ localadminenabled ) {
2013-01-24 19:10:40 +00:00
return " < RunSynchronousCommand wcm:action = \ " add \ " > \ r
<Order> 100 </Order> \ r
<Path> cmd /c %systemroot%\\system32\\net.exe user Administrator / active:no </Path> \ r
</RunSynchronousCommand> " ;
2013-01-10 20:30:44 +00:00
}
return "" ;
}
sub windows_account_data {
#this will add domain accounts if configured to be in active directory
#it will also put in an administrator password for local account, *if* specified
my $ passtab = xCAT::Table - > new ( 'passwd' , - create = > 0 ) ;
my $ useraccountxml = "" ;
$ localadminenabled = 0 ;
if ( $ passtab ) {
my $ passent = $ passtab - > getAttribs ( { key = > "system" , username = > "Administrator" } , [ 'password' ] ) ;
if ( $ passent and $ passent - > { password } ) {
2013-01-24 20:09:19 +00:00
$ useraccountxml = "<AdministratorPassword>\r\n<Value>" . $ passent - > { password } . "</Value>\r\n<PlainText>true</PlainText>\r\n</AdministratorPassword>\r\n" ;
$ useraccountxml . = "<!-- Plaintext=false would only protect against the most cursory over the shoulder glance, this implementation opts not to even give the illusion of privacy by only doing plaintext. -->\r\n" ;
2013-01-10 20:30:44 +00:00
$ localadminenabled = 1 ;
}
}
2013-01-25 21:04:12 +00:00
my $ domain ;
my $ doment ;
my $ domaintab = xCAT::Table - > new ( 'domain' , - create = > 0 ) ;
if ( $ domaintab ) {
2013-03-28 18:59:48 +00:00
$ doment = $ domaintab - > getNodeAttribs ( $ node , [ 'authdomain' , 'type' ] , prefetchcache = > 1 ) ;
}
unless ( $ ::XCATSITEVALS { directoryprovider } eq "activedirectory" or ( $ doment and $ doment - > { type } eq "activedirectory" ) ) {
return $ useraccountxml ;
2013-01-25 21:04:12 +00:00
}
if ( $ doment and $ doment - > { authdomain } ) {
$ domain = $ doment - > { authdomain } ;
} else {
$ domain = $ ::XCATSITEVALS { domain } ;
}
2013-02-04 18:22:12 +00:00
$ useraccountxml . = "<DomainAccounts><DomainAccountList>\r\n<DomainAccount wcm:action=\"add\">\r\n<Group>Administrators</Group>\r\n<Name>Domain Admins</Name>\r\n</DomainAccount>\r\n<Domain>" . $ domain . "</Domain>\r\n</DomainAccountList>\r\n</DomainAccounts>\r\n" ;
2013-01-10 20:30:44 +00:00
return $ useraccountxml ;
}
2013-04-02 19:55:57 +00:00
sub windows_net_cfg {
2013-12-03 07:34:05 +00:00
if ( $ ::XCATSITEVALS { managedaddressmode } =~ /static/ ) { return "<!-- WINCFG Static not supported -->" ; }
unless ( $ ::XCATSITEVALS { managedaddressmode } =~ /autoula/ ) {
# handle the general windows deployment that create interfaces sections from nic table
my $ component_head = '<component name="Microsoft-Windows-TCPIP" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' ;
my $ component_end = '</component>' ;
my $ interfaces_cfg = '<Interfaces>' ;
2013-12-19 09:53:49 +00:00
# get the installnic
my $ nrtab = xCAT::Table - > new ( 'noderes' , - create = > 0 ) ;
my $ installnic ;
if ( $ nrtab ) {
my $ nrent = $ nrtab - > getNodeAttribs ( $ node , [ 'installnic' , 'primarynic' ] ) ;
if ( $ nrent ) {
if ( defined ( $ nrent - > { 'installnic' } ) ) {
$ installnic = $ nrent - > { 'installnic' } ;
} elsif ( defined ( $ nrent - > { 'primarynic' } ) ) {
$ installnic = $ nrent - > { 'primarynic' } ;
}
}
}
# get the site.setinstallnic
my @ ents = xCAT::TableUtils - > get_site_attribute ( "setinstallnic" ) ;
my $ setinstallnic ;
if ( $ ents [ 0 ] =~ /1|yes|y/i ) {
$ setinstallnic = 1 ;
}
2013-12-03 07:34:05 +00:00
my $ nicstab = xCAT::Table - > new ( 'nics' , - create = > 0 ) ;
my $ hasif ;
if ( $ nicstab ) {
my $ nicsent = $ nicstab - > getNodeAttribs ( $ node , [ 'nicips' ] ) ;
if ( $ nicsent - > { nicips } ) {
my @ nics = split ( /,/ , $ nicsent - > { nicips } ) ;
foreach ( @ nics ) {
my $ gateway ;
my $ interface_cfg = '<Interface wcm:action="add">' ;
my ( $ nicname , $ ips ) = split ( /!/ , $ _ ) ;
2013-12-10 12:17:51 +00:00
unless ( $ nicname ) { next ; }
if ( $ nicname =~ /^bmc/ ) { next ; } # do nothing for bmc interface
2013-12-19 09:53:49 +00:00
my $ dosetgw = 0 ;
if ( $ nicname eq $ installnic ) {
if ( $ setinstallnic ) {
# set to static with gateway
$ dosetgw = 1 ;
} else { # else: do nothing means using dhcp
next ;
}
} # else: do not set gateway, since gateway only set for installnic
2013-12-03 07:34:05 +00:00
if ( $ ips ) {
$ interface_cfg . = '<Ipv4Settings><DhcpEnabled>false</DhcpEnabled></Ipv4Settings><Ipv6Settings><DhcpEnabled>false</DhcpEnabled></Ipv6Settings>' ;
$ interface_cfg . = "<Identifier>$nicname</Identifier>" ;
$ interface_cfg . = '<UnicastIpAddresses>' ;
my @ setip = split ( /\|/ , $ ips ) ;
my $ num = 1 ;
foreach my $ ip ( @ setip ) {
my ( $ netmask , $ gw ) = getNM_GW ( $ ip ) ;
unless ( $ netmask ) {
next ;
}
if ( $ gw ) { $ gateway = $ gw ; }
2013-12-19 09:53:49 +00:00
if ( $ gateway eq '<xcatmaster>' ) {
$ gateway = xCAT::NetworkUtils - > my_ip_facing ( $ ip ) ;
}
2013-12-03 07:34:05 +00:00
$ interface_cfg . = '<IpAddress wcm:action="add" wcm:keyValue="' . $ num + + . '">' . $ ip . "/$netmask" . '</IpAddress>' ;
}
2013-12-10 12:17:51 +00:00
if ( $ num eq 1 ) {
# no correct IP with correct network is found
next ;
}
2013-12-03 07:34:05 +00:00
$ interface_cfg . = "</UnicastIpAddresses>"
} else {
# set with dhcp
$ interface_cfg . = '<Ipv4Settings><DhcpEnabled>true</DhcpEnabled></Ipv4Settings><Ipv6Settings><DhcpEnabled>true</DhcpEnabled></Ipv6Settings>' ;
$ interface_cfg . = "<Identifier>$nicname</Identifier>" ;
}
2013-12-19 09:53:49 +00:00
2013-12-03 07:34:05 +00:00
# add the default gateway
2013-12-19 09:53:49 +00:00
if ( $ gateway && $ dosetgw ) {
2013-12-10 12:17:51 +00:00
$ interface_cfg . = '<Routes><Route wcm:action="add"><Identifier>1</Identifier><NextHopAddress>' . $ gateway . '</NextHopAddress><Prefix>0/0</Prefix></Route></Routes>' ;
}
2013-12-03 07:34:05 +00:00
$ interface_cfg . = '</Interface>' ;
$ interfaces_cfg . = $ interface_cfg ;
$ hasif = 1 ;
}
}
}
$ interfaces_cfg . = "</Interfaces>" ;
if ( $ hasif ) {
return "$component_head$interfaces_cfg$component_end" ; #windows default behavior
} else {
return "" ;
}
}
#autoula,
my $ hoststab ;
my $ mactab = xCAT::Table - > new ( 'mac' , - create = > 0 ) ;
unless ( $ mactab ) { die "mac table should always exist prior to template processing when doing autoula" ; }
my $ ent = $ mactab - > getNodeAttribs ( $ node , [ 'mac' ] , prefetchcache = > 1 ) ;
unless ( $ ent and $ ent - > { mac } ) { die "missing mac data for $node" ; }
my $ suffix = $ ent - > { mac } ;
my $ mac = $ suffix ;
$ suffix = lc ( $ suffix ) ;
2013-05-29 18:08:08 +00:00
$ mac =~ s/:/-/g ;
2013-12-03 07:34:05 +00:00
unless ( $ hoststab ) { $ hoststab = xCAT::Table - > new ( 'hosts' , - create = > 1 ) ; }
my $ ulaaddr = autoulaaddress ( $ suffix ) ;
$ hoststab - > setNodeAttribs ( $ node , { ip = > $ ulaaddr } ) ;
return '<component name="Microsoft-Windows-TCPIP" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' . "\r\n<Interfaces><Interface wcm:action=\"add\">\r\n<Ipv4Settings><DhcpEnabled>false</DhcpEnabled></Ipv4Settings><Ipv6Settings><DhcpEnabled>false</DhcpEnabled></Ipv6Settings>\r\n<Identifier>$mac</Identifier>\r\n<UnicastIpAddresses>\r\n<IpAddress wcm:action=\"add\" wcm:keyValue=\"1\">$ulaaddr/64</IpAddress>\r\n</UnicastIpAddresses>\r\n</Interface>\r\n</Interfaces>\r\n</component>\r\n" ;
2013-04-02 19:55:57 +00:00
}
2013-03-25 20:02:04 +00:00
sub windows_dns_cfg {
my $ domain ;
my $ doment ;
my $ noderesent ;
my $ noderestab = xCAT::Table - > new ( "noderes" , - create = > 0 ) ;
unless ( $ noderestab ) { return "" ; }
$ noderesent = $ noderestab - > getNodeAttribs ( $ node , [ 'nameservers' ] , prefetchcache = > 1 ) ;
unless ( $ noderesent and $ noderesent - > { nameservers } ) { return "" ; }
2013-03-25 20:52:21 +00:00
my $ mac = "==PRINIC==" ;
my $ mactab = xCAT::Table - > new ( 'mac' , - create = > 0 ) ;
if ( $ mactab ) {
my $ macent = $ mactab - > getNodeAttribs ( $ node , [ 'mac' ] , prefetchcache = > 1 ) ;
if ( $ macent and $ macent - > { mac } ) {
$ mac = $ macent - > { mac } ;
$ mac =~ s/!.*// ;
$ mac =~ s/\|.*// ;
$ mac =~ s/:/-/g ;
}
}
2013-03-25 20:02:04 +00:00
my $ nameservers = $ noderesent - > { nameservers } ;
my $ domaintab = xCAT::Table - > new ( 'domain' , - create = > 0 ) ;
if ( $ domaintab ) {
$ doment = $ domaintab - > getNodeAttribs ( $ node , [ 'authdomain' ] , prefetchcache = > 1 ) ;
}
if ( $ doment and $ doment - > { authdomain } ) {
$ domain = $ doment - > { authdomain } ;
} else {
$ domain = $ ::XCATSITEVALS { domain } ;
}
2013-03-26 14:38:57 +00:00
my $ componentxml = '<component name="Microsoft-Windows-DNS-Client" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' . "\r\n<DNSDomain>$domain</DNSDomain>\r\n" .
2013-03-25 20:52:21 +00:00
"<Interfaces><Interface wcm:action=\"add\">\r\n<Identifier>$mac</Identifier>\r\n<DNSServerSearchOrder>\r\n" ;
2013-03-25 20:02:04 +00:00
my $ idx = 1 ;
foreach ( split /,/ , $ nameservers ) {
$ componentxml . = "<IpAddress wcm:action=\"add\" wcm:keyValue=\"$idx\">$_</IpAddress>\r\n" ;
$ idx += 1 ;
}
2013-03-25 21:08:26 +00:00
$ componentxml . = "</DNSServerSearchOrder>\r\n</Interface>\r\n</Interfaces>\r\n</component>\r\n" ;
2013-03-25 20:02:04 +00:00
return $ componentxml ;
}
2013-06-19 12:43:34 +00:00
#this will lay out the data from postscripts table in a manner that is appropriate for windows consumption in Microsoft-Windows-Deployment
#component under specialize pass
sub windows_postscripts {
my $ posttab = xCAT::Table - > new ( 'postscripts' , - create = > 0 ) ;
unless ( $ posttab ) { return "" ; }
my $ psent = $ posttab - > getNodeAttribs ( $ node , [ 'postscripts' ] , prefetchcache = > 1 ) ;
unless ( $ psent and $ psent - > { postscripts } ) { return "" ; }
my @ cmds = split /,/ , $ psent - > { postscripts } ;
my $ order = 1 ;
my $ xml ;
my $ pscript ;
2013-06-21 19:13:03 +00:00
foreach $ pscript ( @ cmds ) {
2013-06-19 12:43:34 +00:00
unless ( $ pscript =~ /\\/ ) {
$ pscript = "C:\\xcatpost\\" . $ pscript ;
}
$ xml . = "<RunSynchronousCommand wcm:action=\"add\">\r\n<Order>$order</Order>\r\n<Path>$pscript</Path>\r\n</RunSynchronousCommand>\r\n" ;
}
}
2013-01-10 19:50:43 +00:00
#this will examine table data, decide *if* a Microsoft-Windows-UnattendedJoin is warranted
#there are two variants in how to proceed:
#-Hide domain administrator from node: xCAT will use MACHINEPASSWORD to do joining to AD. Currently requires SSL be enabled on DC. Samba 4 TODO
#-Provide domain administrator credentials, avoiding the SSL scenario. This is by default forbidden as it is high risk for exposing sensitive credentials.
# Also populate MachineObjectOU
sub windows_join_data {
2013-03-28 18:59:48 +00:00
my $ doment ;
my $ domaintab = xCAT::Table - > new ( 'domain' , - create = > 0 ) ;
if ( $ domaintab ) {
2013-03-28 20:52:15 +00:00
$ doment = $ domaintab - > getNodeAttribs ( $ node , [ 'ou' , 'type' , 'authdomain' , 'adminuser' , 'adminpassword' ] , prefetchcache = > 1 ) ;
2013-03-28 18:59:48 +00:00
}
unless ( $ ::XCATSITEVALS { directoryprovider } eq "activedirectory" or ( $ doment and $ doment - > { type } eq "activedirectory" ) ) {
2013-01-10 19:50:43 +00:00
return "" ;
}
#we are still here, meaning configuration has a domain and activedirectory set, probably want to join..
#TODO: provide a per-node 'disable' so that non-AD could be mixed into a nominally AD environment
2013-01-21 14:34:37 +00:00
my $ prejoin = 1 ;
if ( defined $ ::XCATSITEVALS { prejoinactivedirectory } and not $ ::XCATSITEVALS { prejoinactivedirectory } ) {
$ prejoin = 0 ;
}
2013-01-25 21:04:12 +00:00
my $ domain ;
my $ ou ;
if ( $ doment and $ doment - > { ou } ) {
$ ou = $ doment - > { ou } ;
}
if ( $ doment and $ doment - > { authdomain } ) {
$ domain = $ doment - > { authdomain } ;
} else {
$ domain = $ ::XCATSITEVALS { domain } ;
}
2013-02-04 18:22:12 +00:00
my $ componentxml = '<component name="Microsoft-Windows-UnattendedJoin" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' . "\r\n<Identification>\r\n<JoinDomain>" . $ domain . "</JoinDomain>\r\n" ;
2013-01-25 21:04:12 +00:00
if ( $ ou ) {
2013-02-08 19:10:59 +00:00
$ componentxml . = "<MachineObjectOU>" . $ ou . "</MachineObjectOU>\r\n" ;
2013-01-10 19:50:43 +00:00
}
if ( $ prejoin ) {
2013-01-25 21:04:12 +00:00
my $ adinfo = machinepassword ( wantref = > 1 ) ; #TODO: needs rearranging in non prejoin case
2013-01-10 19:50:43 +00:00
#a note, MS is incorrect when they document unsecure join as " UnsecureJoin is performed, by using a null session with a pre-existing account. This means there is no authentication to the domain controller when configuring the machine account; it is done anonymously".
#the more informative bit is http://technet.microsoft.com/en-us/library/cc730845%28v=ws.10%29.aspx which says of 'securejoin': this method is actually less secure because the credentials reside in the ImageUnattend.xml file in plain text.
#xCAT is generating a one-time password that is kept as limited as is feasible for the deployment strategy
#in theory, a domain join will either fail of the one-time password is compromised and changed, or domain
#join will invalidate any 'snooped' one time password
$ componentxml . = "<MachinePassword>" . $ adinfo - > { password } . "</MachinePassword>\n<UnsecureJoin>true</UnsecureJoin>\n" ;
} else { #this is the pass-through credentials case, currrently inaccessible until TODO, this must be used
#with care as used incorrectly, an LDAP manager account is at high risk of compromise
2013-03-28 20:52:15 +00:00
my $ adminuser ;
my $ adminpass ;
if ( $ doment and $ doment - > { adminuser } ) {
$ adminuser = $ doment - > { adminuser } ;
}
if ( $ doment and $ doment - > { adminpassword } ) {
$ adminpass = $ doment - > { adminpassword } ;
}
unless ( $ adminuser and $ adminpass ) {
my $ passtab = xCAT::Table - > new ( 'passwd' , - create = > 0 ) ;
unless ( $ passtab ) { sendmsg ( [ 1 , "Error authenticating to Active Directory" ] , $ node ) ; return ; }
my @ adpents = $ passtab - > getAttribs ( { key = > 'activedirectory' } , [ 'username' , 'password' , 'authdomain' ] ) ;
my $ adpent ;
foreach $ adpent ( @ adpents ) {
if ( $ adpent and $ adpent - > { authdomain } and $ adpent - > { authdomain } ne $ domain ) { next ; }
if ( $ adpent and $ adpent - > { username } and $ adpent - > { password } ) {
$ adminuser = $ adpent - > { username } ;
$ adminpass = $ adpent - > { password } ;
last ;
}
2013-01-25 21:04:12 +00:00
}
}
2013-03-28 20:52:15 +00:00
unless ( $ adminuser and $ adminpass ) { die "Missing active directory admin auth data from passwd table" }
$ componentxml . = "<Credentials><Domain>" . $ domain . "</Domain>\r\n<Username>" . $ adminuser . "</Username>\r\n<Password>" . $ adminpass . "</Password>\r\n</Credentials>\r\n" ;
2013-01-10 19:50:43 +00:00
}
2013-02-04 18:22:12 +00:00
$ componentxml . = "</Identification>\r\n</component>\r\n" ;
2013-01-10 19:50:43 +00:00
}
2013-01-08 19:24:10 +00:00
sub get_win_prodkey {
my $ osvariant = shift ;
my $ keytab = xCAT::Table - > new ( "prodkey" , - create = > 0 ) ;
2013-02-05 18:52:41 +00:00
my $ keyent ;
if ( $ keytab ) {
2013-04-03 20:34:15 +00:00
my @ keyents = $ keytab - > getNodeAttribs ( $ node , [ qw/product key/ ] ) ;
foreach my $ tkey ( @ keyents ) {
if ( $ tkey - > { product } eq $ osvariant ) {
$ keyent = $ tkey ;
last ;
} elsif ( not $ tkey - > { product } ) {
$ keyent = $ tkey ;
}
}
unless ( $ keyent ) {
$ keyent = $ keytab - > getAttribs ( { product = > $ osvariant } , "key" ) ;
}
2013-02-05 18:52:41 +00:00
}
2013-04-17 18:38:22 +00:00
if ( $ keyent and $ keyent - > { key } ) {
2013-01-08 19:24:10 +00:00
return "<ProductKey><WillShowUI>OnError</WillShowUI><Key>" . $ keyent - > { key } . "</Key></ProductKey>" ;
}
if ( $ xCAT:: WinUtils:: kmskeymap { $ osvariant } ) {
return "<ProductKey><WillShowUI>OnError</WillShowUI><Key>" . $ xCAT:: WinUtils:: kmskeymap { $ osvariant } . "</Key></ProductKey>" ;
}
return "" ; #in the event that we have no specified key and no KMS key, then try with no key, user may have used some other mechanism
}
2012-06-20 16:35:21 +00:00
2013-01-28 18:58:00 +00:00
sub managed_address_mode {
return $ ::XCATSITEVALS { managedaddressmode } ;
}
2014-05-08 10:22:23 +00:00
sub get_node_domain {
my $ lcnode = shift ;
if ( $ lcnode eq 'THISNODE' ) {
$ lcnode = $ node ;
}
my $ nd = xCAT::NetworkUtils - > getNodeDomains ( [ $ lcnode ] ) ;
my % nodedomains = %$ nd ;
my $ domain = $ nodedomains { $ lcnode } ;
return $ domain ;
}
2012-07-06 21:09:04 +00:00
sub esxipv6setup {
2013-03-28 18:30:46 +00:00
if ( not $ ::XCATSITEVALS { managedaddressmode } or $ ::XCATSITEVALS { managedaddressmode } =~ /v4/ ) { return "" ; } # blank line for ipv4 schemes
my $ v6addr ;
if ( $ ::XCATSITEVALS { managedaddressmode } eq "autoula" ) {
2012-07-06 21:09:04 +00:00
my $ hoststab ;
my $ mactab = xCAT::Table - > new ( 'mac' , - create = > 0 ) ;
2013-03-28 18:30:46 +00:00
my $ ent = $ mactab - > getNodeAttribs ( $ node , [ 'mac' ] , prefetchcache = > 1 ) ;
2012-07-06 21:09:04 +00:00
my $ suffix = $ ent - > { mac } ;
$ suffix = lc ( $ suffix ) ;
unless ( $ mactab ) { die "mac table should always exist prior to template processing when doing autoula" ; }
#in autoula, because ESXi weasel doesn't seemingly grok IPv6 at all, we'll have to do it in %pre
unless ( $ hoststab ) { $ hoststab = xCAT::Table - > new ( 'hosts' , - create = > 1 ) ; }
2013-03-28 18:30:46 +00:00
$ v6addr = autoulaaddress ( $ suffix ) ;
$ hoststab - > setNodeAttribs ( $ node , { ip = > $ v6addr } ) ;
} else {
my $ hoststab = xCAT::Table - > new ( 'hosts' , - create = > 0 ) ;
unless ( $ hoststab ) { die "unable to proceed, no hosts table to read from" }
my $ ent = $ hoststab - > getNodeAttribs ( $ node , [ "ip" ] , prefetchcache = > 1 ) ;
unless ( $ ent and $ ent - > { ip } ) { die "no hosts table entry with viable IP in hosts table for $node" }
$ v6addr = $ ent - > { ip } ;
unless ( $ v6addr =~ /:/ ) { die "incorrect format for static ipv6 in hosts table for $node" }
}
2013-05-06 14:03:06 +00:00
return 'esxcfg-vmknic -i ' . $ v6addr . '/64 "Management Network"' . " #ESXISTATICV6\n" ;
2012-07-06 21:09:04 +00:00
}
2012-07-10 05:59:35 +00:00
2014-04-17 10:04:54 +00:00
2012-06-20 16:35:21 +00:00
sub kickstartnetwork {
2014-04-11 09:40:34 +00:00
my $ line = "network --onboot=yes --bootproto=" ;
my $ hoststab ;
2012-06-20 16:35:21 +00:00
my $ mactab = xCAT::Table - > new ( 'mac' , - create = > 0 ) ;
2012-06-25 20:05:11 +00:00
unless ( $ mactab ) { die "mac table should always exist prior to template processing when doing autoula" ; }
2013-04-02 19:55:57 +00:00
my $ ent = $ mactab - > getNodeAttribs ( $ node , [ 'mac' ] , prefetchcache = > 1 ) ;
2012-06-20 16:35:21 +00:00
unless ( $ ent and $ ent - > { mac } ) { die "missing mac data for $node" ; }
my $ suffix = $ ent - > { mac } ;
$ suffix = lc ( $ suffix ) ;
if ( $ ::XCATSITEVALS { managedaddressmode } eq "autoula" ) {
2012-06-25 20:05:11 +00:00
unless ( $ hoststab ) { $ hoststab = xCAT::Table - > new ( 'hosts' , - create = > 1 ) ; }
2012-06-20 16:35:21 +00:00
$ line . = "static --device=$suffix --noipv4 --ipv6=" ;
2012-06-25 20:05:11 +00:00
my $ ulaaddr = autoulaaddress ( $ suffix ) ;
$ hoststab - > setNodeAttribs ( $ node , { ip = > $ ulaaddr } ) ;
$ line . = $ ulaaddr ;
2013-03-27 20:43:00 +00:00
} elsif ( $ ::XCATSITEVALS { managedaddressmode } =~ /static/ ) {
2014-04-11 09:40:34 +00:00
my ( $ ipaddr , $ hostname , $ gateway , $ netmask ) = xCAT::NetworkUtils - > getNodeNetworkCfg ( $ node ) ;
unless ( $ ipaddr ) { die "cannot resolve the network configuration of $node" ; }
2014-04-17 10:04:54 +00:00
if ( $ gateway eq '<xcatmaster>' ) {
$ gateway = xCAT::NetworkUtils - > my_ip_facing ( $ ipaddr ) ;
}
2014-04-11 09:40:34 +00:00
$ line . = "static --device=$suffix --ip=$ipaddr --netmask=$netmask --gateway=$gateway --hostname=$hostname " ;
2014-04-17 10:04:54 +00:00
my % nameservers = % { xCAT::NetworkUtils - > getNodeNameservers ( [ $ node ] ) } ;
my @ nameserverARR = split ( "," , $ nameservers { $ node } ) ;
2014-04-11 09:40:34 +00:00
my @ nameserversIP ;
foreach ( @ nameserverARR )
{
2014-04-17 10:04:54 +00:00
my $ ip ;
if ( $ _ eq '<xcatmaster>' ) {
$ ip = xCAT::NetworkUtils - > my_ip_facing ( $ gateway ) ;
} else {
( undef , $ ip ) = xCAT::NetworkUtils - > gethostnameandip ( $ _ ) ;
}
2014-04-11 09:40:34 +00:00
push @ nameserversIP , $ ip ;
2014-04-17 10:04:54 +00:00
2014-04-11 09:40:34 +00:00
}
2014-05-08 10:22:23 +00:00
#there is no network option to set dns search domain in kickstart, it will be set in %post
2014-04-11 09:40:34 +00:00
if ( scalar @ nameserversIP ) {
$ line . = " --nameserver=" . join ( "," , @ nameserversIP ) ;
}
#return "#KSNET static unsupported";
2012-06-20 16:35:21 +00:00
} else {
2012-08-05 05:04:07 +00:00
$ line . = "dhcp --device=$suffix" ;
2012-06-20 16:35:21 +00:00
}
return $ line ;
}
2014-04-11 09:40:34 +00:00
sub yast2network {
my $ line ;
my $ hoststab ;
my $ mactab = xCAT::Table - > new ( 'mac' , - create = > 0 ) ;
unless ( $ mactab ) { die "mac table should always exist prior to template processing when doing autoula" ; }
my $ ent = $ mactab - > getNodeAttribs ( $ node , [ 'mac' ] , prefetchcache = > 1 ) ;
unless ( $ ent and $ ent - > { mac } ) { die "missing mac data for $node" ; }
my $ suffix = $ ent - > { mac } ;
$ suffix = lc ( $ suffix ) ;
if ( $ ::XCATSITEVALS { managedaddressmode } eq "autoula" ) {
#TODO
return "#YAST2NET autoula unsupported"
} elsif ( $ ::XCATSITEVALS { managedaddressmode } =~ /static/ ) {
my ( $ ipaddr , $ hostname , $ gateway , $ netmask ) = xCAT::NetworkUtils - > getNodeNetworkCfg ( $ node ) ;
unless ( $ ipaddr ) { die "cannot resolve the network configuration of $node" ; }
2014-04-17 10:04:54 +00:00
if ( $ gateway eq '<xcatmaster>' ) {
$ gateway = xCAT::NetworkUtils - > my_ip_facing ( $ ipaddr ) ;
}
my % nameservers = % { xCAT::NetworkUtils - > getNodeNameservers ( [ $ node ] ) } ;
my @ nameserverARR = split ( "," , $ nameservers { $ node } ) ;
2014-04-11 09:40:34 +00:00
my @ nameserversIP ;
foreach ( @ nameserverARR )
{
2014-04-17 10:04:54 +00:00
my $ ip ;
if ( $ _ eq '<xcatmaster>' ) {
$ ip = xCAT::NetworkUtils - > my_ip_facing ( $ gateway ) ;
} else {
( undef , $ ip ) = xCAT::NetworkUtils - > gethostnameandip ( $ _ ) ;
}
2014-04-11 09:40:34 +00:00
push @ nameserversIP , $ ip ;
2014-04-17 10:04:54 +00:00
2014-04-11 09:40:34 +00:00
}
2014-04-17 10:04:54 +00:00
2014-04-11 09:40:34 +00:00
# get the domains for each node - one call for all nodes in hosts file
my $ nd = xCAT::NetworkUtils - > getNodeDomains ( [ $ node ] ) ;
my % nodedomains = %$ nd ;
my $ domain = $ nodedomains { $ node } ;
my $ networkhash = {
'networking' = > [
{
'dns' = > [
{
'domain' = > [
"$domain"
] ,
'dhcp_hostname' = > [
{
'content' = > 'false' ,
'config:type' = > 'boolean'
}
] ,
'dhcp_resolv' = > [
{
'content' = > 'false' ,
'config:type' = > 'boolean'
}
] ,
'nameservers' = > [
{
'config:type' = > 'list' ,
2014-04-17 10:04:54 +00:00
'nameserver' = > [ @ nameserversIP ]
2014-04-11 09:40:34 +00:00
}
] ,
'hostname' = > [
$ hostname
] ,
'searchlist' = > [
{
'search' = > [
$ domain
] ,
'config:type' = > 'list'
}
]
}
] ,
'interfaces' = > [
{
'interface' = > [
{
'bootproto' = > [
'static'
] ,
'startmode' = > [
'onboot'
] ,
'netmask' = > [
$ netmask
] ,
'device' = > [
'eth0'
] ,
'ipaddr' = > [
$ ipaddr
]
}
] ,
'config:type' = > 'list'
}
] ,
'routing' = > [
{
'ip_forward' = > [
{
'content' = > 'false' ,
'config:type' = > 'boolean'
}
] ,
'routes' = > [
{
'route' = > [
{
'destination' = > [
'default'
] ,
'gateway' = > [
$ gateway
] ,
'netmask' = > [
'-'
] ,
'device' = > [
'-'
]
}
] ,
'config:type' = > 'list'
}
]
}
]
}
]
} ;
my $ xml = new XML:: Simple ( KeepRoot = > 1 ) ;
$ line = $ xml - > XMLout ( $ networkhash ) ;
#return "#KSNET static unsupported";
} else {
my $ networkhash = {
'networking' = > [
{
'dns' = > [
{
'domain' = > [
'local'
] ,
'dhcp_hostname' = > [
{
'content' = > 'true' ,
'config:type' = > 'boolean'
}
] ,
'hostname' = > [
'linux'
] ,
'dhcp_resolv' = > [
{
'content' = > 'true' ,
'config:type' = > 'boolean'
}
]
}
] ,
'interfaces' = > [
{
'interface' = > [
{
'startmode' = > [
'onboot'
] ,
'bootproto' = > [
'dhcp'
] ,
'device' = > [
'eth0'
]
}
] ,
'config:type' = > 'list'
}
] ,
'routing' = > [
{
'ip_forward' = > [
{
'content' = > 'false' ,
'config:type' = > 'boolean'
}
] ,
'routes' = > [
{
'config:type' = > 'list'
}
]
}
]
}
]
} ;
my $ xml = new XML:: Simple ( KeepRoot = > 1 ) ;
$ line = $ xml - > XMLout ( $ networkhash ) ;
}
2014-04-17 10:04:54 +00:00
2014-04-11 09:40:34 +00:00
return $ line ;
}
2012-06-20 16:35:21 +00:00
sub autoulaaddress {
my $ suffix = shift ;
my $ prefix = $ ::XCATSITEVALS { autoulaprefix } ;
$ suffix =~ /(..):(..:..):(..:..):(..)/ ;
my $ leadbyte = $ 1 ;
2012-06-20 18:06:30 +00:00
my $ mask = ( ( hex ( $ leadbyte ) & 2 ) ^ 2 ) ;
2012-06-20 16:35:21 +00:00
if ( $ mask ) {
2012-06-20 18:06:30 +00:00
$ leadbyte = hex ( $ leadbyte ) | $ mask ;
2012-06-20 16:35:21 +00:00
} else {
2012-06-20 18:06:30 +00:00
$ leadbyte = hex ( $ leadbyte ) & 0xfd ; #mask out the one bit
2012-06-20 16:35:21 +00:00
}
2012-06-20 18:06:30 +00:00
$ suffix = sprintf ( "%02x$2ff:fe$3$4" , $ leadbyte ) ;
2012-06-20 16:35:21 +00:00
return $ prefix . $ suffix ;
}
2010-03-09 22:00:00 +00:00
sub machinepassword {
2013-01-10 19:50:43 +00:00
my % funargs = @ _ ;
if ( $ lastmachinepassdata - > { password } ) { #note, this should only happen after another call
2011-09-30 18:07:03 +00:00
#to subvars that does *not* request reuse
#the issue being avoiding reuse in the installmonitor case
#subvars function clears this if appropriate
2013-01-10 19:50:43 +00:00
if ( $ funargs { wantref } ) {
return $ lastmachinepassdata ;
}
return $ lastmachinepassdata - > { password } ;
2011-09-30 18:07:03 +00:00
}
2013-01-10 19:50:43 +00:00
my $ passdata ;
2010-03-09 22:00:00 +00:00
my $ domaintab = xCAT::Table - > new ( 'domain' ) ;
2010-05-19 21:03:40 +00:00
$ ENV { HOME } = '/etc/xcat' ;
$ ENV { LDAPRC } = 'ad.ldaprc' ;
2010-03-09 22:00:00 +00:00
my $ ou ;
2013-01-25 21:04:12 +00:00
my $ domain ;
2010-03-09 22:00:00 +00:00
if ( $ domaintab ) {
2013-01-25 21:04:12 +00:00
my $ ouent = $ domaintab - > getNodeAttribs ( $ node , [ 'ou' , 'authdomain' ] , prefetchcache = > 1 ) ;
2010-03-09 22:00:00 +00:00
if ( $ ouent and $ ouent - > { ou } ) {
$ ou = $ ouent - > { ou } ;
}
2013-01-25 21:04:12 +00:00
if ( $ ouent and $ ouent - > { authdomain } ) {
$ domain = $ ouent - > { authdomain } ;
}
2010-03-09 22:00:00 +00:00
}
2013-01-10 19:50:43 +00:00
$ passdata - > { ou } = $ ou ;
2012-05-18 06:14:35 +00:00
#my $sitetab = xCAT::Table->new('site');
#unless ($sitetab) {
# return "ERROR: unable to open site table";
#}
#(my $et) = $sitetab->getAttribs({key=>"domain"},'value');
2013-01-25 21:04:12 +00:00
unless ( $ domain ) {
2012-08-09 04:00:45 +00:00
my @ domains = xCAT::TableUtils - > get_site_attribute ( "domain" ) ;
2012-05-18 06:14:35 +00:00
my $ tmp = $ domains [ 0 ] ;
if ( defined ( $ tmp ) ) {
$ domain = $ tmp ;
} else {
2013-01-25 21:04:12 +00:00
return "ERROR: no domain set in site table or in domain.authdomain for $node" ;
}
2010-03-09 22:00:00 +00:00
}
2013-01-10 19:50:43 +00:00
$ passdata - > { domain } = $ domain ;
2010-03-09 22:00:00 +00:00
my $ realm = uc ( $ domain ) ;
$ realm =~ s/\.$// ;
$ realm =~ s/^\.// ;
$ ENV { KRB5CCNAME } = "/tmp/xcat/krbcache.$realm.$$" ;
unless ( $ loggedrealms { $ realm } ) {
my $ passtab = xCAT::Table - > new ( 'passwd' , - create = > 0 ) ;
unless ( $ passtab ) { sendmsg ( [ 1 , "Error authenticating to Active Directory" ] , $ node ) ; return ; }
2013-01-25 21:04:12 +00:00
my @ adpents = $ passtab - > getAttribs ( { key = > 'activedirectory' } , [ 'username' , 'password' , 'authdomain' ] ) ;
my $ adpent ;
my $ username ;
my $ password ;
foreach $ adpent ( @ adpents ) {
if ( $ adpent and $ adpent - > { authdomain } and $ adpent - > { authdomain } ne $ domain ) { next ; }
if ( $ adpent and $ adpent - > { username } and $ adpent - > { password } ) {
$ username = $ adpent - > { username } ;
$ password = $ adpent - > { password } ;
last ;
}
}
unless ( $ username and $ password ) {
2010-03-09 22:00:00 +00:00
return "ERROR: activedirectory entry missing from passwd table" ;
}
my $ err = xCAT::ADUtils:: krb_login ( username = > $ adpent - > { username } , password = > $ adpent - > { password } , realm = > $ realm ) ;
if ( $ err ) {
return "ERROR: authenticating to Active Directory" ;
}
$ loggedrealms { $ realm } = 1 ;
}
2012-05-18 06:14:35 +00:00
#my $server = $sitetab->getAttribs({key=>'directoryserver'},['value']);
my $ server ;
2012-08-09 04:00:45 +00:00
my @ servers = xCAT::TableUtils - > get_site_attribute ( "directoryserver" ) ;
2013-01-25 21:04:12 +00:00
my $ tmp = $ servers [ 0 ] ;
2012-05-18 06:14:35 +00:00
if ( defined ( $ tmp ) ) {
$ server = $ tmp ;
2010-03-09 22:00:00 +00:00
} else {
$ server = '' ;
if ( $ netdnssupport ) {
my $ res = Net::DNS::Resolver - > new ;
my $ query = $ res - > query ( "_ldap._tcp.$domain" , "SRV" ) ;
if ( $ query ) {
foreach my $ srec ( $ query - > answer ) {
$ server = $ srec - > { target } ;
}
}
}
unless ( $ server ) {
sendmsg ( [ 1 , "Unable to determine a directory server to communicate with, try site.directoryserver" ] ) ;
return ;
}
}
2013-01-10 19:50:43 +00:00
$ passdata - > { dc } = $ server ;
2010-03-09 22:00:00 +00:00
my % args = (
node = > $ node ,
dnsdomain = > $ domain ,
directoryserver = > $ server ,
changepassondupe = > 1 ,
) ;
if ( $ ou ) { $ args { ou } = $ ou } ;
my $ data = xCAT::ADUtils:: add_host_account ( % args ) ;
if ( $ data - > { error } ) {
return "ERROR: " . $ data - > { error } ;
} else {
2013-01-10 19:50:43 +00:00
$ passdata - > { password } = $ data - > { password } ;
$ lastmachinepassdata = $ passdata ;
if ( $ funargs { wantref } ) {
return $ passdata ;
}
2010-03-09 22:00:00 +00:00
return $ data - > { password } ;
}
}
2007-10-26 22:44:33 +00:00
sub includefile
{
2009-07-10 18:34:09 +00:00
my $ file = shift ;
my $ special = shift ;
2010-08-04 19:42:56 +00:00
my $ pkglist = shift ; #1 means package list,
#2 means pattern list, pattern list starts with @,
#3 means remove package list, packages to be removed start with -.
2009-07-10 18:34:09 +00:00
my $ text = "" ;
2007-10-26 22:44:33 +00:00
unless ( $ file =~ /^\// ) {
$ file = $ idir . "/" . $ file ;
}
2010-03-09 22:00:00 +00:00
open ( INCLUDE , $ file ) || return "#INCLUDEBAD:cannot open $file#" ;
2009-07-10 18:34:09 +00:00
2010-04-13 17:30:54 +00:00
my $ pkgb = "" ;
my $ pkge = "" ;
if ( $ pkglist ) {
2010-07-30 20:20:51 +00:00
if ( $ pkglist == 2 ) {
$ pkgb = "<pattern>" ;
$ pkge = "</pattern>" ;
} else {
$ pkgb = "<package>" ;
$ pkge = "</package>" ;
}
}
2009-07-10 18:34:09 +00:00
while ( <INCLUDE> ) {
2010-07-30 20:20:51 +00:00
if ( $ pkglist == 1 ) {
2010-04-13 17:30:54 +00:00
s/#INCLUDE:/#INCLUDE_PKGLIST:/ ;
2010-07-30 20:20:51 +00:00
} elsif ( $ pkglist == 2 ) {
s/#INCLUDE:/#INCLUDE_PTRNLIST:/ ;
2010-08-04 19:42:56 +00:00
} elsif ( $ pkglist == 3 ) {
s/#INCLUDE:/#INCLUDE_RMPKGLIST:/ ;
2010-04-13 17:30:54 +00:00
}
2010-07-30 20:20:51 +00:00
if ( ( $ _ =~ /^\s*#/ ) || ( $ _ =~ /^\s*$/ ) ) {
2010-04-13 17:30:54 +00:00
$ text . = "$_" ;
} else {
2010-08-04 19:42:56 +00:00
my $ tmp = $ _ ;
chomp ( $ tmp ) ; #remove return char
$ tmp =~ s/\s*$// ; #removes trailing spaces
next if ( ( $ pkglist == 1 ) && ( ( $ tmp =~ /^\s*@/ ) || ( $ tmp =~ /^\s*-/ ) ) ) ; #for packge list, do not include the lines start with @
2010-07-30 20:20:51 +00:00
if ( $ pkglist == 2 ) { #for pattern list, only include the lines start with @
2010-08-04 19:42:56 +00:00
if ( $ tmp =~ /^\s*@(.*)/ ) {
$ tmp = $ 1 ;
$ tmp =~ s/^\s*// ; #removes leading spaces
} else { next ; }
} elsif ( $ pkglist == 3 ) { #for rmpkg list, only include the lines start with -
if ( $ tmp =~ /^\s*-(.*)/ ) {
$ tmp = $ 1 ;
$ tmp =~ s/^\s*// ; #removes leading spaces
2010-07-30 20:20:51 +00:00
} else { next ; }
2010-08-04 19:42:56 +00:00
}
$ text . = "$pkgb$tmp$pkge\n" ;
2010-04-13 17:30:54 +00:00
}
2009-07-10 18:34:09 +00:00
}
close ( INCLUDE ) ;
if ( $ special ) {
$ text =~ s/\$/\\\$/g ;
$ text =~ s/`/\\`/g ;
}
2007-10-26 22:44:33 +00:00
2009-07-10 18:34:09 +00:00
chomp ( $ text ) ;
return ( $ text ) ;
2007-10-26 22:44:33 +00:00
}
sub command
{
my $ command = shift ;
my $ r ;
# if(($r = `$command`) == 0) {
# chomp($r);
# return($r);
# }
# else {
# return("#$command: failed $r#");
# }
$ r = `$command` ;
chomp ( $ r ) ;
return ( $ r ) ;
}
sub envvar
{
my $ envvar = shift ;
if ( $ envvar =~ /^\$/ ) {
$ envvar =~ s/^\$// ;
}
return ( $ ENV { $ envvar } ) ;
}
sub genpassword {
#Generate a pseudo-random password of specified length
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 crydb
{
my $ result = tabdb ( @ _ ) ;
2013-01-14 14:56:44 +00:00
# 1 - MD5, 5 - SHA256, 6 - SHA512
unless ( ( $ result =~ /^\$1\$/ ) || ( $ result =~ /^\$5\$/ ) || ( $ result =~ /^\$6\$/ ) ) {
2007-10-26 22:44:33 +00:00
$ result = crypt ( $ result , '$1$' . genpassword ( 8 ) ) ;
}
return $ result ;
}
sub tabdb
{
my $ table = shift ;
my $ key = shift ;
my $ field = shift ;
2008-03-20 17:38:25 +00:00
my $ blankok = shift ;
2012-10-26 13:49:47 +00:00
2013-02-21 06:30:07 +00:00
2013-04-17 06:38:42 +00:00
if ( % ::GLOBAL_TAB_HASH && defined ( $ ::GLOBAL_TAB_HASH { $ table } ) ) {
2013-02-21 06:30:07 +00:00
if ( ! defined ( $ ::GLOBAL_TAB_HASH { $ table } { $ key } ) ) {
return "''" ;
}
2012-11-01 06:06:57 +00:00
if ( defined ( $ ::GLOBAL_TAB_HASH { $ table } { $ key } { $ field } ) ) {
2013-01-22 08:30:27 +00:00
return "'" . $ ::GLOBAL_TAB_HASH { $ table } { $ key } { $ field } . "'" ;
2012-11-01 06:06:57 +00:00
} else {
2013-02-21 06:30:07 +00:00
return "''" ;
2012-11-01 06:06:57 +00:00
}
2013-02-21 06:30:07 +00:00
2012-10-26 13:49:47 +00:00
}
2007-10-26 22:44:33 +00:00
my $ tabh = xCAT::Table - > new ( $ table ) ;
2008-03-10 14:20:47 +00:00
unless ( $ tabh ) {
$ tmplerr = "Unable to open table named $table" ;
if ( $ table =~ /\.tab/ ) {
2008-03-10 14:45:35 +00:00
$ tmplerr . = " (.tab should not be specified as part of the table name in xCAT 2, as seems to be the case here)" ;
2008-03-10 14:20:47 +00:00
}
return "" ;
}
2007-10-26 22:44:33 +00:00
my $ ent ;
2009-06-17 21:03:08 +00:00
my $ bynode = 0 ;
2007-10-26 22:44:33 +00:00
if ( $ key eq "THISNODE" or $ key eq '$NODE' ) {
$ ent = $ tabh - > getNodeAttribs ( $ node , [ $ field ] ) ;
2008-05-16 19:03:18 +00:00
$ key = "node=$node" ;
2007-10-26 22:44:33 +00:00
} else {
my % kp ;
foreach ( split /,/ , $ key ) {
my $ key ;
my $ val ;
2009-06-17 21:03:08 +00:00
if ( $ _ eq 'THISNODE' or $ _ eq '$NODE' ) {
$ bynode = 1 ;
} else {
( $ key , $ val ) = split /=/ , $ _ ;
$ kp { $ key } = $ val ;
}
}
if ( $ bynode ) {
my @ ents = $ tabh - > getNodeAttribs ( $ node , [ keys % kp , $ field ] ) ;
my $ tent ; #Temporary ent
TENT: foreach $ tent ( @ ents ) {
foreach ( keys % kp ) {
unless ( $ kp { $ _ } eq $ tent - > { $ _ } ) {
next TENT ;
}
} #If still here, we found it
$ ent = $ tent ;
}
} else {
( $ ent ) = $ tabh - > getAttribs ( \ % kp , $ field ) ;
2007-10-26 22:44:33 +00:00
}
}
$ tabh - > close ;
2007-11-19 19:45:11 +00:00
unless ( $ ent and defined ( $ ent - > { $ field } ) ) {
2008-03-20 17:38:25 +00:00
unless ( $ blankok ) {
2012-02-21 06:53:54 +00:00
if ( $ field eq "xcatmaster" ) {
2012-08-09 04:00:45 +00:00
my $ ipfn = xCAT::NetworkUtils - > my_ip_facing ( $ node ) ;
2012-02-21 06:53:54 +00:00
if ( $ ipfn ) {
return $ ipfn ;
}
}
2012-02-06 22:15:50 +00:00
#$tmplerr="Unable to find requested $field from $table, with $key";
2013-10-08 19:36:59 +00:00
my $ savekey = $ key ;
$ key = '$NODE' ; # make sure we use getNodeAttribs when get_replacement
# calls this routine (tabdb)
2012-02-06 22:15:50 +00:00
my $ rep = get_replacement ( $ table , $ key , $ field ) ;
2013-10-08 19:36:59 +00:00
$ key = $ savekey ; # restore just in case we rely on the node=$node setting
2012-02-06 22:15:50 +00:00
if ( $ rep ) {
return tabdb ( $ rep - > [ 0 ] , $ rep - > [ 1 ] , $ rep - > [ 2 ] ) ;
} else {
$ tmplerr = "Unable to find requested $field from $table, with $key"
}
2008-03-20 17:38:25 +00:00
}
2007-11-19 19:45:11 +00:00
return "" ;
#return "#TABLEBAD:$table:field $field not found#";
2007-10-26 22:44:33 +00:00
}
return $ ent - > { $ field } ;
#if($key =~ /^\$/) {
# $key =~ s/^\$//;
# $key = $ENV{$key};
#}
#if($field =~ /^\$/) {
# $field =~ s/^\$//;
# $field = $ENV{$field};
#}
#if($field == '*') {
# $field = 1;
# $all = 1;
#}
#--$field;
#if($field < 0) {
# return "#TABLE:field not found#"
#}
#open(TAB,$table) || \
# return "#TABLE:cannot open $table#";
#while(<TAB>) {
# if(/^$key(\t|,| )/) {
# m/^$key(\t|,| )+(.*)/;
# if($all == 1) {
# return "$2";
# }
# @fields = split(',',$2);
# if(defined $fields[$field]) {
# return "$fields[$field]";
# }
# else {
# return "#TABLE:field not found#"
# }
# }
#}
#close(TAB);
#return "#TABLE:key not found#"
}
2012-02-06 22:15:50 +00:00
sub get_replacement {
my $ table = shift ;
my $ key = shift ;
my $ field = shift ;
my $ rep ;
if ( exists ( $ tab_replacement { "$table:$field" } ) ) {
my $ repstr = $ tab_replacement { "$table:$field" } ;
if ( $ repstr ) {
my @ a = split ( ':' , $ repstr ) ;
if ( @ a > 2 ) {
$ rep = \ @ a ;
} else {
$ rep - > [ 0 ] = $ a [ 0 ] ;
$ rep - > [ 1 ] = $ key ;
$ rep - > [ 2 ] = $ a [ 1 ] ;
}
}
}
return $ rep ;
}
2013-05-16 13:56:17 +00:00
# This routine is used in the creation of the mypostscript file and is defined
# in /opt/xcat/share/xcat/templates/mypostcript/mypostscript.tmpl
# It cannot be moved to another perl library, due to migration problems.
#
2012-10-12 06:06:48 +00:00
sub enablesshbetweennodes
{
2013-05-16 13:56:17 +00:00
my $ node = shift ;
my $ result ;
2012-10-12 06:06:48 +00:00
2013-05-16 13:56:17 +00:00
my $ enablessh = xCAT::TableUtils - > enablessh ( $ node ) ;
2012-10-12 06:06:48 +00:00
if ( $ enablessh == 1 ) {
2013-01-22 08:30:27 +00:00
$ result = "'YES'" ;
2012-10-12 06:06:48 +00:00
} else {
2013-01-22 08:30:27 +00:00
$ result = "'NO'" ;
2012-10-12 06:06:48 +00:00
}
return $ result ;
}
2013-12-03 07:34:05 +00:00
sub getNM_GW ()
{
my $ ip = shift ;
my $ nettab = xCAT::Table - > new ( "networks" ) ;
if ( $ nettab ) {
my @ nets = $ nettab - > getAllAttribs ( 'net' , 'mask' , 'gateway' ) ;
foreach my $ net ( @ nets ) {
if ( xCAT::NetworkUtils:: isInSameSubnet ( $ net - > { 'net' } , $ ip , $ net - > { 'mask' } , 0 ) ) {
return ( xCAT::NetworkUtils:: formatNetmask ( $ net - > { 'mask' } , 0 , 1 ) , $ net - > { 'gateway' } ) ;
}
}
}
return ( undef , undef ) ;
}
2012-10-12 06:06:48 +00:00
2007-10-26 22:44:33 +00:00
1 ;