1

I don't know if this is possible, but going to ask anyways.

I am trying to Kickstart newer servers of us with CentOS 7. So far I got most working, however for some reason if I use variables in the %pre section of my Kickstart script, then it does not get parsed over to the configuration at all. Therefor I am starting to think this is not even possible?

This is what I have in the %pre section of my Kickstart:

%pre --log /tmp/pre-install.log

hostname=serverA120
ip=100.110.120.130
IFS=. read ip1 ip2 ip3 ip4 <<< "$ip"

Than during the Kickstart it should use the above filled-in information:

network  --bootproto=static --device=eth0 --gateway=100.110.$ip3.1 --ip=$ip --nameserver=1.1.1.1 --netmask=255.255.255.0
network  --hostname=$hostname.example.com

And in the %post section I also try to use the variables from %pre:

sed -i'' -e '/HOSTNAME=/d' /etc/sysconfig/network
echo HOSTNAME=$hostname.example.com >> /etc/sysconfig/network
echo GATEWAY=100.110.$ip3.1 >> /etc/sysconfig/network

echo BOOTPROTO=static >> /etc/sysconfig/network-scripts/ifcfg-eth0
echo IPADDR=$ip >> /etc/sysconfig/network-scripts/ifcfg-eth0
echo NETMASK=255.255.255.0 >> /etc/sysconfig/network-scripts/ifcfg-eth0
echo BROADCAST=100.110.$ip3.255 >> /etc/sysconfig/network-scripts/ifcfg-eth0
echo NETWORK=100.110.$ip3.0 >> /etc/sysconfig/network-scripts/ifcfg-eth0
echo GATEWAY=100.110.$ip3.1  >> /etc/sysconfig/network-scripts/ifcfg-eth0

echo $hostname.example.com >> /etc/hostname
sudo hostnamectl set-hostname $hostname.example.com

I checked the ifcfg-eth0 physically after I couldn't reach the server anymore and it showed the following:

IPADDR=
BROADCAST=100.110..255
NETWORK=100.110..0
GATEWAY=100.110..1

I also checked /etc/hostname:

$hostname.example.com

So variables are not being parsed into the Kickstart. Am I doing something wrong or is it simply not possible? And is there an alternative solution perhaps for this?

Ofcourse I can manually adjust all lines manually before and after, but I wanted to make this as easy as possible without editing everything manually. In other words, I just want to fill in 2 lines and that rest gets configured as I want. This would make things easier with Kickstarting multiple servers on the long run.

I have no clue what I am doing wrong, but checking ifcfg-eth0 and hostname, it clearly shows the pre-entered variables are not being used? But like I said above, maybe it's simply not possible, that or I am using it incorrectly.

And no I don't want to use DHCP or similar. Because I still have to change it manually afterwards. I just want to fill in the first two lines in %pre (hostname and ip) and that it gets used automatically during the complete installation (and in %post).

1
+50

You can't use variables from one block with another one as they are separate scripts executed at different points in time; These code sections will be split and placed into single separate files and then executed (not even) in the order you write them, meaning that if you have 3 %pre sections, they won't get necessarily be executed in order, so keep that into account. Also, you cannot use these variables with any other section of the kickstart.

One idea would be to use satellite files where to keep your data (like you write a /tmp/file in your %pre and then get it back in your %post... that you can do)

I went a different way, I literally have created a full bait-and-switch for anaconda that allows me to place a fake kickstart on disk, and then run a script in place to substitute variables in the likes of %%IP%% or %%HOSTNAME%% with a sed.

Anyway you don't need to do any of this, you can just place the setting of ip1 ip2 ip3 ip4 at the top of your %post block, this way you're gonna have the variables set.

then you can simply write your files as you were doing before in your post block.

Skip the "network" lines in the kickstart and just use network --activate [--device=DEVICENAME] (Add --device if you have multiple and want to just use 1)

This below is just FYI:

when using %pre %post you don't have access to BASH, it's just Bourne shell.

the kickstart allows you to use "--interpreter=/bin/bash" in your %pre/%post line but after extensive testing in the past I've found it to be wonky and not working all the time, so usually I add the shebang right at the first line of the block.

    %post --log=/root/post.log
    #!/bin/bash
    ##
    [... code ...]
    %end

this should allow you to use BASH instead of Bourne shell.

2
  • Thank you for explaining. Highly appreciated. The reason I wanted to use variables at the start is that it was easier to change. But I guess I will go back to my original method (and replace IP and hostname manually twice by hand, not that much work, but my idea was easier). In regards to "FYI"-part. Wouldn't it be an idea to apply both? So use "--interpreter=/bin/bash" along with "#!/bin/bash" or do you still recommend only using: #!/bin/bash?
    – HudsonHawk
    Jul 25 '19 at 8:12
  • 1
    It definitely cannot hurt to use both :), even if a script had 2 shebangs on 2 rows, only the first one would be used, the second one would be a comment. You can even think of using the linux append cmdline with dracut, look here fedoraproject.org/wiki/Dracut/Options#Network you need dracut-network
    – MatteoBee
    Jul 25 '19 at 19:26
1

I use something similar to get dhcp settings. I expect you could take a few extra steps to get a static IP address.

%pre
echo "network  --bootproto=dhcp --device=eth0 --ipv6=auto --activate --hostname renameme.ipa.smith122.com" > /tmp/network.ks
for x in $( cat /proc/cmdline );
do
   case $x in
      SERVERNAME*)
         eval $x
         echo "network  --bootproto=dhcp --device=eth0 --ipv6=auto --activate --hostname ${SERVERNAME}.ipa.example.com" > /tmp/network.ks
         ;;
      NOTIFYEMAIL*)
         eval $x
         echo "${NOTIFYEMAIL}" > /mnt/sysroot/root/notifyemail.txt
         ;;
   esac
done

And then outside the %pre and %post, just in general in the file, you need:

%include /tmp/network.ks

For you, you'd probably want a line to resemble:

network --bootproto=static --ip=10.0.2.15 --netmask=255.255.255.0 --gateway=10.0.2.254 --nameserver=10.0.2.1

References

  1. https://sysadmin.compxtreme.ro/automatically-set-the-hostname-during-kickstart-installation/
  2. My own blog post: https://bgstack15.wordpress.com/2019/07/25/use-virt-install-to-fully-automate-the-install-for-centos-fedora-with-kickstart/
  3. https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/installation_guide/s1-kickstart2-options found via Internet search for kickstart network
1

While the accepted answer is generally correct, and a good explanation of what's going on, I though I'd add some clarity that's missing and then show an actual working implementation variation I'm using which demonstrates some of this.

First, lets drive home the "variables" point. The %pre and %post blocks are simply wrappers around arbitrary code which has no meaning to the installer. It sees everything in those blocks as simply text that gets handed off to the --interpreter. In fact, you could use %pre --interpreter=/bin/sh and %post --interpreter=/usr/bin/python, in which case variables in the two blocks would not even be syntactically compatible. So, variable "scope" is first local to a %pre/%post block at the very least, then would be further restricted according to the "scope" rules of the language specified by the --interpreter option.

Now, an important point the accepted answer didn't get into is the %pre block gets executed in the install environment. The install environment is like a live-cd

  • It's running a RAM resident filesystem.
  • You only have access to the commands and utilities that are included on the installer filesystem.
  • Devices and their names in the "install" environment may differ from the "installed" environment.

For example, this %pre --log /tmp/pre-install.log may not do what you expect. If the install fails for some reason before the installer boots into the new install you could use the installer shell to cat that file. But once the reboot happens, anything that was written to the temporary installer filesystem will be lost.

Also, this is technically incorrect:

One idea would be to use satellite files where to keep your data (like you write a /tmp/file in your %pre and then get it back in your %post... that you can do)

You could do that, but only if you write it to a file system that will persist across reboots, like a USB, iSCSI, NFS, CIFS, etc., mount.

With that in mind, follow the KISS (Keep It Simple...) principal when it comes to the %pre selection. You may not have access to the more advanced commands/tools/languages; it will depend on what is, and is not, in the installer package and various distros and versions may change that over time.

Conversely, you pretty much have card blanche in the %post block, since by that time you'll have access to everything that you specified in the %packages block.

While you want to keep the %pre block simple in terms of the tools and languages used, the more you do to configure the system using the installers commands, the less you'll be forced to "patch" the configuration in the %post block.


Working Example - Variation

When provisioning new hosts I start by collecting and/or generating three things (for the purpose of this example); MAC Address, IP Address, Host Name. If I have a large block of those they usually go into a configuration spreadsheet. The next step is to create reservations in DHCP which connects the the baremetal or virtual MAC to it's assigned IP. The IP and hostname then go into the DNS forward and reverse lookup zones. You can use formulas in the spreadsheet to generate the DHCP and DNS entries so it becomes a cut and past exercise. Once DHCP and DNS are done you just network boot the box and the correct configuration just happens. I find a DHCP reservation to be a small price to pay for the consistency and efficiency of deploying and even redeploying server instances.

This is the kickstart file, which has been stripped down to little more than the relevant entries

#version=RHEL8

text

%include /tmp/network.ks

eula --agreed
reboot
skipx

%pre
#!/bin/bash

DEVICE=$(ip r|grep default|grep  -oP '(?<=dev )\S*')
declare -A value
while IFS= read -r line; do
  kvp=${line##DHCP4.OPTION\[*\]:*[ ][ ]}
  value+=([${kvp% = *}]=${kvp#* = })
done <<< $(nmcli -f dhcp4 device show $DEVICE)

echo "network --device link --bootproto static --ip ${value[ip_address]} --netmask ${value[subnet_mask]} --gateway ${value[routers]} --hostname ${value[host_name]}.${value[domain_name]} --nameserver ${value[domain_name_servers]} --onboot yes --noipv6" > /tmp/network.ks

%end

%post --log=/root/install-post.log

cat << EOF >> /etc/hosts
$(hostname -i)        $(hostname -s) $(hostname -f)
EOF

%end

Since I've already created a DHCP reservation for the "Static" configuration I wish to use, in the %pre block I use nmcli to get the relevant DHCP parameters and use them to dynamically generate the network... command for the installer to use. That dynamically generated file is then included in the body of the kickstart script.

One thing that may seem a little confusing here is the use of $DEVICE to query the dhcp4 parameters, yet I'm using network --device link .... The reason is the differences between the installers devices, which is what I need to query, and the name of the network device(s) in the installed system, which I am not forcing by specifying the "first active link", and allowing the installer to name devices as it sees fit. I've had trouble in the past by assuming the active name in the installers environment will be the same in the installed environment... and then things went sideways.

In the %post block I do one thing I need that isn't done by the network... command, add the IP and hostname to the hosts file. If all the prior steps have configured the system correctly by the time the %post block executes you can grab whatever you need straight out of the running configuration... you don't need to persist any of the %pre variables since the system will be running on them at this point.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.