#!/usr/bin/perl # IBM(c) 2010 EPL license http://www.eclipse.org/legal/epl-v10.html #------------------------------------------------------- =head1 mkay4z Description: Create an autoyast template for Linux on System z. Author: Thang Pham (thang.pham@us.ibm.com) Returns: Autoyast template Usage: mkay4z [conf_file] [ref_template], where [conf_file]: File containing Linux configuration [ref_template]: Reference autoyast template to build off of Example: # ./mkay4z conf.txt ref.sles11.s390x.tmpl > custom.sles11.s390x.tmpl =cut #------------------------------------------------------- use strict; use warnings; # Check arguments if(@ARGV != 2) { print < custom.sles11.s390x.tmpl END exit(); } # Get conf file and reference template my $file = $ARGV[0]; my $tmpl = $ARGV[1]; # Create parameters to search for my @search = ('dasd', 'partitions', 'software'); # Get parameters from conf file my %parms = getParms($file); # Set parameters for networking and root password $parms{'hosts'} = '[host_address=replace_host_address,name=replace_long_name replace_short_name]'; $parms{'dns'} = '[hostname=replace_hostname,dhcp_hostname=true,dhcp_resolv=true,domain=replace_domain,nameserver=replace_nameserver]'; $parms{'interfaces'} = '[device=replace_device,bootproto=dhcp,lladdr=replace_lladdr,chanids=replace_ccw_chan_ids]'; $parms{'root_password'} = 'replace_root_password'; # Check that all parameters are given my $missing = ''; foreach(@search) { if(!$parms{$_}) { $missing .= "$_ "; } } # If there are missing paramters if($missing) { print "Please supply the following parameters in $file: $missing"; exit(); } # Create section my $dasdSection = createDasd($parms{'dasd'}); # Create section my $hostsSection = createHosts($parms{'hosts'}); # Create section my $dnsSection = createDns($parms{'dns'}); # Create section my ($interfacesSection, %interface) = createInterfaces($parms{'interfaces'}); # Create section my $dasdModulesSection = createDasdModules($parms{'dasd'}); my $nicModulesSection = createNicModules(%interface); # Create section my $partitionsSection = createPartitions($parms{'partitions'}); # Create software section my $softwareSection = createSoftware($parms{'software'}); # Create password section my $passwordSection = <$parms{'root_password'} END # Create routes section my $routesSection = createRoutes($parms{'interfaces'}); # Create scripts section my $scriptsSection = createScripts(%interface); # Begin to build template # Edit template by replacing place holders: # insert_devices # insert_hosts # insert_dns # insert_interfaces # insert_modules # insert_partitioning_drives # insert_software_pattern # insert_root_password # insert_routes # Read in autoyast template open(FILE, $tmpl); # Go through each line while(my $ln = ) { # If the line matches the pattern to replace, print replacement if($ln =~ 'insert_devices') { print $dasdSection; } elsif($ln =~ 'insert_hosts') { print $hostsSection; } elsif($ln =~ 'insert_dns') { print $dnsSection; } elsif($ln =~ 'insert_interfaces') { print $interfacesSection; } elsif($ln =~ 'insert_modules') { print $dasdModulesSection; print $nicModulesSection; } elsif($ln =~ 'insert_partitioning_drives') { print $partitionsSection; } elsif($ln =~ 'insert_software_pattern') { print $softwareSection; } elsif($ln =~ 'insert_root_password') { print $passwordSection; } elsif($ln =~ 'insert_routes') { print $routesSection; } elsif($ln =~ '') { # Print line $ln =~ s/\r//g; # Remove return carriage print $ln; print $scriptsSection; } else { # Print line $ln =~ s/\r//g; # Remove return carriage print $ln; } } close(FILE); #------------------------------------------------------- =head3 getParms Description : Get the parameters in the conf file Arguments : Conf file Returns : Hash table of parameters Example : my %parms = getParms($file); =cut #------------------------------------------------------- sub getParms { my ($file) = @_; # Read in file open(FILE, $file); # Go through line in the file my %parms; my $name = ''; my $tmp = ''; while(my $ln = ) { # If the line contains ={, get the parameter name if ($ln =~ /={/) { ($name, $tmp) = split(/={/, $ln, 2); $parms{$name} = ''; } if ($name) { # Append line to parameter $parms{$name} = $parms{$name} . trim($ln); } } close(FILE); # Remove curly brackets foreach my $key(keys %parms) { $parms{$key} =~ s/(.*=\{|\})//g; } return %parms; } #------------------------------------------------------- =head3 trim Description : Trim the whitespaces in a string Arguments : String Returns : Trimmed string Example : my $str = trim($str); =cut #------------------------------------------------------- sub trim { # Get string my ($str) = @_; # Trim right $str =~ s/\s*$//; # Trim left $str =~ s/^\s*//; return ($str); } #------------------------------------------------------- =head3 createDasd Description : Create the section Arguments : Dasd attached to server Returns : section Example : my $section = createDasd($dasd); =cut #------------------------------------------------------- sub createDasd { # Get string my ($str) = @_; # Split the dasd my @args = split(/\],/, $str); # Remove square brackets my $i; for($i = 0; $i < @args; $i++) { $args[$i] =~ s/(\[|\])//g; $args[$i] = trim($args[$i]); } # Create hash table for each dasd my %dasd; my @tmp; my $pos; my $length; foreach(@args) { # Split the arguments # e.g. 0.0.0100,dasd_eckd_mod,(/dev/dasda,/dev/dasdb) @tmp = split(/,/,$_,4); $tmp[0] = trim($tmp[0]); $dasd{$tmp[0]}{'channel'} = $tmp[0]; $dasd{$tmp[0]}{'modules'} = trim($tmp[1]); $dasd{$tmp[0]}{'dev_name'} = trim($tmp[2]); # Remove brackets $tmp[3] = trim($tmp[3]); $dasd{$tmp[0]}{'partition_info'} = substr($tmp[3], 1, length($tmp[3])-2); } # Create section # # # None # none # 0.0.0100 # true # /dev/dasda # # /dev/dasda # /dev/disk/by-path/ccw-0.0.0100 # # DASD # io_subchannel # # # true # true # # # dasd_eckd_mod # # # # # # false # /dev/dasda1 (Linux native) # # # # true # 1 # rw # # # # 0.0.0100 # my $xml = ''; my @partInfo; foreach my $id(sort (keys %dasd)){ # If this dasd is to be used for Linux if ($dasd{$id}{'partition_info'} =~ 'Linux native') { $xml .= < None none $id true $dasd{$id}{'dev_name'} $dasd{$id}{'dev_name'} /dev/disk/by-path/ccw-$id DASD io_subchannel true true $dasd{$id}{'modules'} false $dasd{$id}{'partition_info'} true 1 rw $id END } else { $xml .= < None none $id $dasd{$id}{'dev_name'} $dasd{$id}{'dev_name'} /dev/disk/by-path/ccw-$id DASD io_subchannel true true $dasd{$id}{'modules'} true $dasd{$id}{'partition_info'} 16 128 $id END } } return $xml; } #------------------------------------------------------- =head3 createInterfaces Description : Create the section Arguments : Interfaces attached to server Returns : section Example : my $section = createInterfaces($interfaces); =cut #------------------------------------------------------- sub createInterfaces { # Get string my ($str) = @_; # Split the interfaces my @device = split(/\],/,$str); # Remove square brackets my $i; for($i = 0; $i < @device; $i++) { $device[$i] =~ s/(\[|\])//g; $device[$i] = trim($device[$i]); } # Create hash table for each interface my %interface; my @args; my $id; my $name; my $value; # Loop through each interface foreach(@device) { # Split the arguments # e.g. device=eth0,bootproto=static,broadcast=10.1.100.255,... @args = split(/,/,$_); # Device name should always be the first index $args[0] =~ s/device=//g; $id = trim($args[0]); # Go through each attribute and set hash table for($i = 1; $i < @args; $i++) { # Get the attribute name value pair ($name, $value) = split(/=/, $args[$i], 2); $name = trim($name); $value = trim($value); $interface{$id}{$name} = $value; } } # Create section # # static # 10.1.100.255 # eth0 # 10.1.100.100 # OSA Express Network card (0.0.0800) # 255.255.255.0 # 25 # auto # # # The layout is different for DHCP: # # dhcp # eth0 # 02:00:00:FF:FF:FF # auto # no # my $xml = ''; foreach my $id(keys %interface){ # Create static interface if($interface{$id}{'bootproto'} eq 'static') { $xml .= < $interface{$id}{'bootproto'} $interface{$id}{'broadcast'} $id $interface{$id}{'ipaddr'} $interface{$id}{'name'} $interface{$id}{'netmask'} 25 auto END } # Create DHCP interface else { $xml .= < $interface{$id}{'bootproto'} $id $interface{$id}{'lladdr'} auto no END } } return ($xml, %interface); } #------------------------------------------------------- =head3 createPartitions Description : Create the section Arguments : Partitions to create on server Returns : section Example : my $section = createPartitions($partitions); =cut #------------------------------------------------------- sub createPartitions { # Get string my ($str) = @_; # Split the interfaces my @device = split(/\],/,$str); # Remove square brackets my $i; for($i = 0; $i < @device; $i++) { $device[$i] =~ s/(\[|\])//g; $device[$i] = trim($device[$i]); } # Create hash table for each partitions my %partitions; my @args; my $id; # Loop through each partitions foreach(@device) { # Split the arguments # e.g. device=/dev/dasda,filesystem=ext3,(mount=/;size=4G),(lvm_group=VG;size=max) # device=/dev/VG,(lv_name=LV_home;filesystenm=ext3;mount=/home;size=3G),(lv_name=LV_opt;filesystem=ext3;mount=/opt;size=3G) @args = split(/,/,$_,2); # Device name should always be the first index $args[0] =~ s/device=//g; $id = trim($args[0]); # Partition setup should always be the second index $partitions{$id}{'partition'} = trim($args[1]); } # Create section # # /dev/dasda # # # true # ext3 # true # / # path # 131 # 1 # primary # max # # # all # # # The layout is different for LVM: # # /dev/dasdb # true # # # true # false # ext3 # false # false # VG # path # false # max # # # all # my $xml = ''; my %layoutAttr; my @layout; my @attrs; my $name; my $value; # Go through each partition foreach my $id(sort (keys %partitions)){ # Split partition layout @layout = split(/,/, $partitions{$id}{'partition'}); %layoutAttr = (); # Go through each layout for($i = 0; $i < @layout; $i++) { # Remove parenthesis $layout[$i] =~ s/(\(|\))//g; $layout[$i] = trim($layout[$i]); # Split layout attributes @attrs = split(/;/, $layout[$i]); foreach(@attrs) { ($name, $value) = split(/=/, $_, 2); $name = trim($name); $value = trim($value); $layoutAttr{$i}{$name} = $value; } } # Create head $xml .= < $id END # Go through each layout and create section(s) my $isLvm; foreach my $p(keys %layoutAttr){ $isLvm = 0; # If this partition is an LVM group if($layoutAttr{$p}{'lvm_group'}) { $xml .= < true false $layoutAttr{$p}{'filesystem'} false false $layoutAttr{$p}{'lvm_group'} path 142 1 false $layoutAttr{$p}{'size'} END } # If this partition is an LVM volume elsif($layoutAttr{$p}{'lv_name'}) { $isLvm = 1; $xml .= < true false $layoutAttr{$p}{'filesystem'} true acl,user_xattr $layoutAttr{$p}{'lv_name'} $layoutAttr{$p}{'mount'} path 131 false $layoutAttr{$p}{'size'} END } # Not an LVM else { $xml .= < true $layoutAttr{$p}{'filesystem'} true $layoutAttr{$p}{'mount'} path 131 1 primary $layoutAttr{$p}{'size'} END } } # Create tail if(!$isLvm) { $xml .= < all END } else { $xml .= < 4M CT_LVM all END } } return $xml; } #------------------------------------------------------- =head3 createHosts Description : Create the section Arguments : Hosts to be created on server Returns : section Example : my $section = createHosts($hosts); =cut #------------------------------------------------------- sub createHosts { # Get string my ($str) = @_; # Split the hosts my @hosts = split(/\],/,$str); # Remove square brackets my $i; for($i = 0; $i < @hosts; $i++) { $hosts[$i] =~ s/(\[|\])//g; $hosts[$i] = trim($hosts[$i]); } # Create hash table for each host my %host; my @args; my $id; my $name; my $value; # Loop through each host foreach(@hosts) { # Split the arguments # e.g. host_address=10.1.100.100,name=gpok100.endicott.ibm.com gpok100 @args = split(/,/,$_); # Host address should always be the first index $args[0] =~ s/host_address=//g; $id = trim($args[0]); # Go through each attribute and set hash table for($i = 1; $i < @args; $i++) { # Get the attribute name value pair ($name, $value) = split(/=/, $args[$i], 2); $name = trim($name); $value = trim($value); $host{$id}{$name} = $value; } } # Create section # e.g. # # 10.1.100.100 # # gpok100.endicott.ibm.com gpok100 # # my $xml = ''; # Create standard localhost entry $xml .= < 127.0.0.1 localhost END # Create host entries foreach my $id(keys %host){ $xml .= < $id $host{$id}{'name'} END } return $xml; } #------------------------------------------------------- =head3 createDns Description : Create the section Arguments : DNS to use Returns : section Example : my $section = createDns($dns); =cut #------------------------------------------------------- sub createDns { # Get string my ($str) = @_; # Split the hosts my @dns = split(/\],/,$str); # Remove square brackets my $i; for($i = 0; $i < @dns; $i++) { $dns[$i] =~ s/(\[|\])//g; $dns[$i] = trim($dns[$i]); } # Create hash table for each DNS my %dn; my @args; my $id; my $name; my $value; # Loop through each host foreach(@dns) { # Split the arguments # e.g. hostname=gpok100,domain=endicott.ibm.com,nameserver=10.1.100.1 @args = split(/,/,$_); # Hostname should always be the first index $args[0] =~ s/hostname=//g; $id = trim($args[0]); # Go through each attribute and set hash table for($i = 1; $i < @args; $i++) { # Get the attribute name value pair ($name, $value) = split(/=/, $args[$i], 2); $name = trim($name); $value = trim($value); $dn{$id}{$name} = $value; } } # Create section # false # false # endicott.ibm.com # gpok100 # # 10.1.100.100 # my $xml = ''; foreach my $id(keys %dn){ $xml .= <$dn{$id}{'dhcp_hostname'} $dn{$id}{'dhcp_resolv'} $dn{$id}{'domain'} $id $dn{$id}{'nameserver'} END } return $xml; } #------------------------------------------------------- =head3 createDasdModules Description : Create the section for each dasd attached Arguments : Dasd attached to server Returns : section Example : my $section = createDasdModules($modules); =cut #------------------------------------------------------- sub createDasdModules { # Get string my ($str) = @_; # Split the dasd my @args = split(/\],/,$str); # Remove square brackets my $i; for($i = 0; $i < @args; $i++) { $args[$i] =~ s/(\[|\])//g; $args[$i] = trim($args[$i]); } # Create hash table for each dasd my %modules; my @tmp; foreach(@args) { # Split the arguments # e.g. 0.0.0100,dasd_eckd_mod,/dev/dasda,(/dev/dasda1;/dev/dasda2) @tmp = split(/,/,$_,4); $tmp[0] = trim($tmp[0]); $modules{$tmp[0]}{'channel'} = $tmp[0]; $modules{$tmp[0]}{'module'} = trim($tmp[1]); } # Create section # # dasd-bus-ccw-0.0.0100 # dasd_eckd_mod # # my $xml = ''; foreach my $id(keys %modules){ $xml .= < dasd-bus-ccw-$id $modules{$id}{'module'} END } return $xml; } #------------------------------------------------------- =head3 createNicModules Description : Create the section for each interface attached Arguments : Hash table of interfaces Returns : section Example : my $section = createNicModules(%interfaces); =cut #------------------------------------------------------- sub createNicModules { # Get hash table my (%interface) = @_; # Create section # # 0.0.0800 0.0.0801 0.0.0802 # FOOBAR # 3 # eth0 # qeth # # my $xml = ''; my $script = ''; foreach my $id(sort (keys %interface)){ $xml .= < $interface{$id}{'chanids'} FOOBAR 3 $id qeth END } return $xml; } #------------------------------------------------------- =head3 createSoftware Description : Create the section Arguments : Software to be installed Returns : section Example : my $section = createSoftware($dns); =cut #------------------------------------------------------- sub createSoftware { # Get string my ($str) = @_; # Split the software # e.g. base,gnome my @software = split(/,/,$str); # Create section # Basis-Devel # Minimal # base # documentation # file_server # gnome # print_server # x11 my $xml = ''; foreach (@software){ $xml .= <$_ END } return $xml; } #------------------------------------------------------- =head3 createRoutes Description : Create the section Arguments : Routing configuration Returns : section Example : my $section = createRoutes($route); =cut #------------------------------------------------------- sub createRoutes { # Get string my ($str) = @_; # Split the interfaces my @device = split(/\],/,$str); # Remove square brackets my $i; for($i = 0; $i < @device; $i++) { $device[$i] =~ s/(\[|\])//g; $device[$i] = trim($device[$i]); } # Create hash table for each interface my %interface; my @args; my $id; my $name; my $value; # Loop through each interface foreach(@device) { # Split the arguments # e.g. device=eth0,bootproto=static,broadcast=10.1.100.255,... @args = split(/,/,$_); # Device name should always be the first index $args[0] =~ s/device=//g; $id = trim($args[0]); # Go through each attribute and set hash table for($i = 1; $i < @args; $i++) { # Get the attribute name value pair ($name, $value) = split(/=/, $args[$i], 2); $name = trim($name); $value = trim($value); $interface{$id}{$name} = $value; } } # Create section # false # # # default # eth0 # 10.1.100.1 # - # # my $xml = ''; my $dest = ''; foreach my $id(sort (keys %interface)){ if(!$dest) { # The first interface is the default route $dest = 'default'; } else { # Get network $dest = substr($interface{$id}{'ipaddr'}, 0, rindex($interface{$id}{'ipaddr'}, '.')); $dest .= ".0"; } # Do not set route for DHCP interface if(!($interface{$id}{'bootproto'} eq 'dhcp')) { $xml .= < $dest $id $interface{$id}{'netmask'} END } } return $xml; } #------------------------------------------------------- =head3 createScripts Description : Create the section to configure interfaces Arguments : Hash table of interfaces to configure with post-scripts Returns : section Example : my $section = createScripts(%interfaces); =cut #------------------------------------------------------- sub createScripts { # Get hash table my (%interface) = @_; # Default route is being added by autoyast (bug) # Setting default route in post-script my $xml = ''; my $script = ''; foreach my $id(sort (keys %interface)){ # Set the default route for the firs interface # Do not set default route for DHCP interface if(!$script && !($interface{$id}{'bootproto'} eq 'dhcp')) { $script .= < /etc/sysconfig/network/routes END last; } } # Create section if($script) { $xml .= < END } return $xml; }