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 ;
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 ;
}
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 ) {
$ doneincludes = 1 ;
2010-04-15 18:31:46 +00:00
if ( $ inc =~ /#INCLUDE_PKGLIST:[^#^\n]+#/ ) {
2010-04-13 17:30:54 +00:00
$ doneincludes = 0 ;
2010-04-15 18:31:46 +00:00
$ inc =~ s/#INCLUDE_PKGLIST:([^#^\n]+)#/includefile($1, 0, 1)/eg ;
2010-04-13 17:30:54 +00:00
}
2010-07-30 20:20:51 +00:00
if ( $ inc =~ /#INCLUDE_PTRNLIST:[^#^\n]+#/ ) {
$ doneincludes = 0 ;
$ inc =~ s/#INCLUDE_PTRNLIST:([^#^\n]+)#/includefile($1, 0, 2)/eg ;
}
2010-08-04 19:42:56 +00:00
if ( $ inc =~ /#INCLUDE_RMPKGLIST:[^#^\n]+#/ ) {
$ doneincludes = 0 ;
$ inc =~ s/#INCLUDE_RMPKGLIST:([^#^\n]+)#/includefile($1, 0, 3)/eg ;
}
2010-04-15 18:31:46 +00:00
if ( $ inc =~ /#INCLUDE:[^#^\n]+#/ ) {
2007-10-26 22:44:33 +00:00
$ doneincludes = 0 ;
2010-04-15 18:31:46 +00:00
$ inc =~ s/#INCLUDE:([^#^\n]+)#/includefile($1, 0, 0)/eg ;
2007-10-26 22:44:33 +00:00
}
}
2012-03-23 08:30:50 +00:00
2013-05-31 08:34:10 +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 ) {
2013-09-13 14:16:13 +00:00
if ( $ platform =~ /^(rh|SL|centos|fedora)$/ ) {
2013-05-31 08:34:10 +00:00
if ( $ c == 0 ) {
2013-05-31 08:47:19 +00:00
# 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.
2013-05-31 08:34:10 +00:00
$ source_in_pre . = "echo 'url --url http://'\$nextserver'/$pkgdir' >> /tmp/repos" ;
2013-05-31 08:47:19 +00:00
$ source . = "url --url http://#TABLE:noderes:\$NODE:nfsserver#/$pkgdir\n" ; #For rhels5.9
2013-05-31 08:34:10 +00:00
} else {
2013-05-31 08:47:19 +00:00
$ 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
}
2013-05-31 08:34:10 +00:00
} 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> " ;
2013-06-04 07:54:52 +00:00
$ 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>" ;
2013-05-31 08:34:10 +00:00
}
$ c + + ;
}
$ inc =~ s/#INSTALL_SOURCES#/$source/g ;
$ inc =~ s/#INSTALL_SOURCES_IN_PRE#/$source_in_pre/g ;
}
2012-03-23 08:30:50 +00:00
#Support hierarchical include
$ inc =~ s/#ENV:([^#]+)#/envvar($1)/eg ;
if ( $ inc =~ /#INCLUDE:[^#^\n]+#/ ) {
$ inc =~ s/#INCLUDE:([^#^\n]+)#/includefile($1, 0, 0)/eg ;
}
2007-10-26 22:44:33 +00:00
#ok, now do everything else..
$ inc =~ s/#TABLE:([^:]+):([^:]+):([^#]+)#/tabdb($1,$2,$3)/eg ;
2008-03-20 17:38:25 +00:00
$ inc =~ s/#TABLEBLANKOKAY:([^:]+):([^:]+):([^#]+)#/tabdb($1,$2,$3,'1')/eg ;
2010-04-15 18:31:46 +00:00
$ inc =~ s/#INCLUDE_NOP:([^#^\n]+)#/includefile($1,1,0)/eg ;
$ inc =~ s/#INCLUDE_PKGLIST:([^#^\n]+)#/includefile($1,0,1)/eg ;
2010-07-30 20:20:51 +00:00
$ inc =~ s/#INCLUDE_PTRNLIST:([^#^\n]+)#/includefile($1,0,2)/eg ;
2010-08-04 19:42:56 +00:00
$ inc =~ s/#INCLUDE_RMPKGLIST:([^#^\n]+)#/includefile($1,0,3)/eg ;
2010-04-15 18:31:46 +00:00
$ inc =~ s/#INCLUDE:([^#^\n]+)#/includefile($1, 0, 0)/eg ;
2013-05-30 09:24:24 +00:00
$ 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/#ESXIPV6SETUP#/esxipv6setup()/eg ;
2013-01-08 19:24:10 +00:00
$ inc =~ s/#WINTIMEZONE#/xCAT::TZUtils::get_wintimezone()/eg ;
$ inc =~ s/#WINPRODKEY:([^#]+)#/get_win_prodkey($1)/eg ;
2013-04-02 19:55:57 +00:00
$ inc =~ s/#WINNETCFG#/windows_net_cfg()/eg ;
2013-01-10 19:50:43 +00:00
$ inc =~ s/#WINADJOIN#/windows_join_data()/eg ;
2013-06-19 12:43:34 +00:00
$ inc =~ s/#WINPOSTSCRIPTS#/windows_postscripts()/eg ;
2013-03-25 20:02:04 +00:00
$ inc =~ s/#WINDNSCFG#/windows_dns_cfg()/eg ;
2013-01-10 20:30:44 +00:00
$ inc =~ s/#WINACCOUNTDATA#/windows_account_data()/eg ;
$ inc =~ s/#WINDISABLENULLADMIN#/windows_disable_null_admin()/eg ;
2013-01-28 18:58:00 +00:00
$ inc =~ s/#MANAGEDADDRESSMODE#/managed_address_mode()/eg ;
2013-01-02 20:09:46 +00:00
$ inc =~ s/#HOSTNAME#/$node/g ;
2009-09-30 17:27:42 +00:00
To make the code easier to maintain we decided not to select autoyast config template file (compute.sdk.sles11.tmpl/compute.sles11), instead if the user want to do a SDK included full install, he should prepare a customized template from compute.sdk.sles11.tmpl, and copy it to /install/custom directory.
This is for SLES 11 SP1 SDK DVD support (Patch 1)
====================================================================
Patch Reason: Design changed, To make the code easier to maintain
we decided not to automate select autoyast config template file
(compute.sdk.sles11.tmpl/compute.sles11),
Patch detail: If the user want to do a SDK DVD included full install,
he/she should prepare a customized template originated from
compute.sdk.sles11.tmpl, and copy it under /install/custom
====================================================================
====================================================================
Target Dist: SLES 11 SP1, for both full install and statelite install
Aim: To enable users to install packages from SDK DVD during installation
user impact: If the user add packages in .pkglist files, he/she should first do 'copycds' using SDK DVD iso.
For full install, the user should prepare a .tmpl file for autoyast
By-effect: N/A
Limitations: 2nd installation DVD and 2nd SDK DVD not supported, both carries source packages.
It seems they are not recognized by autoyast, and it's of no use to install sources pkgs on CNs.
====================================================================
git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@9980 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd
2011-06-29 10:03:58 +00:00
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 ;
2009-07-10 18:34:09 +00:00
2012-06-25 12:03:03 +00:00
#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 ) ;
#the content of the specified file is a script which can write partition definition into /tmp/partitionfile
if ( $ scriptflag ) {
2012-07-10 05:59:35 +00:00
#for redhat/sl/centos/kvm/fedora
if ( $ inc =~ /#XCAT_PARTITION_START#/ ) {
2012-11-05 08:29:42 +00:00
my $ tempstr = "%include /tmp/partitionfile\n" ;
2012-07-10 05:59:35 +00:00
$ inc =~ s/#XCAT_PARTITION_START#[\s\S]*#XCAT_PARTITION_END#/$tempstr/ ;
#modify the content in the file, and write into %pre part
2012-07-12 10:26:10 +00:00
$ partcontent = "cat > /tmp/partscript << EOFEOF\n" . $ partcontent . "\nEOFEOF\n" ;
2012-07-10 05:59:35 +00:00
$ 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 -->/ ) {
2012-07-12 10:26:10 +00:00
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" ;
2012-07-10 05:59:35 +00:00
$ partcontent . = "chmod 755 /tmp/partscript\n" ;
$ partcontent . = "/tmp/partscript\n" ;
$ inc =~ s/#XCA_PARTITION_SCRIPT#/$partcontent/ ;
}
2012-06-25 12:03:03 +00:00
}
else {
$ partcontent =~ s/\s$// ;
2012-07-05 07:42:13 +00:00
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/ ;
}
2012-06-25 12:03:03 +00:00
}
}
}
2008-03-10 14:20:47 +00:00
if ( $ tmplerr ) {
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 } ;
}
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
2012-06-20 16:35:21 +00:00
sub kickstartnetwork {
2012-08-09 02:05:53 +00:00
my $ line = "network --onboot=yes --bootproto=" ;
2012-06-25 20:05:11 +00:00
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/ ) {
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 ;
}
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 ;