How do I pass arguments from the PXE command line to a kickstart %pre, %post script?
Basically I want an ARGV like usage on the PXE command line, but I can't see any documentation to do this.
basically I want to pass something like
scientific-linux-6 HOSTNAME VLAN
then in %pre hit some APIs to get the networking info I need to append it to the KS config. This part is easy, if I have the parameters.
Finally in %post I want to kick off a chef run and boot strap to chef server. This also needs to know hostname / domain name ( basically have hostname -f not blow up ), but this shouldn't be too bad if I can complete the above. Sadly, this was my original goal, but then it failed when I realized I didn't have the hostname set yet.
Here is what I have learned so far.
$ cat linux-install/msgs/param.msg
09Kernel Parameter Help07
Some kernel parameters can be specified on the command line and will be
passed to the running kernel. This does not include options to modules
such as ethernet cards or devices such as CD-ROM drives.
To pass an option to the kernel, use the following format:
0flinux <options>07
If a different installation mode is desired, enter it after the option(s).
For example, to install on a system with 128MB of RAM using expert mode,
type the following:
0flinux mem=128M expert07
To pass options to modules, you will need to use the expert mode to disable
PCI autoprobing. When the installation asks for your device type that needs
an option or parameter passed to it, there will be a place to type those
in at that time.
Sweet!? So that means on PXE I can go like...
scientific-linux-6 linux ARGV_APPEND
Right?
Then getting things into %pre and %post I found This presentation and a few other mentions
Stick this at the top of the %pre section, and it will take anything of the form var=value
from /proc/cmdline and turn it into a variable you can use directly
set -- `cat /proc/cmdline`
for I in $*; do case "$I" in *=*) eval $I;; esac; done
So that means I can say
scientific-linux-6 linux HOSTNAME=foo.example.com, VLAN=ddd
Right?
Then in %pre That means I can
Hit my API to get IP, mask, gateway and then change network to something like
network --bootproto=static --ip=10.0.2.15 --netmask=255.255.255.0
--gateway=10.0.2.254 --nameserver=10.0.2.1
As described Here
Then that sets up us in %post for our chef-client run.
My question is. Does it sound like this will work? Is there a better way? Surely someone else has done this before?
Update ( Solution implemented based on answer )
On the PXE command line I ended up passing options
$ hotbox linux prefix_varname="foo" prefix_another_var="bar"
( everything after linux
is put on /proc/cmdline . hotbox
was the PXE label. )
Then in %post
I parsed /proc/cmdline (in Ruby) looking for all the variables that matched /prefix_*/
and turned them into a hash. This lead to passing it off the chef for further configuration based on the results of a web request.
Note: Razor wasn't around when I did all this. I personally wasn't satisfied with razor, and we are still using more or less the above method.
With simple boolean options, I've done a grep
in /proc/cmdline
, which is very easy. For key-value options, the set
trick seems handy, though I haven't tried it. Specific answers to your questions:
1) Yes, it sounds like this will work. I've done very similar things with kickstart and /proc/cmdline
.
2) No, I don't believe there is any better way. The kernel exposes its command line options in /proc/cmdline
, and kickstart doesn't provide any high-level mechanisms for dealing with kernel command line options.
3) Yes, this has been done before. Try it out, and come back if you can't make it work.
A few additional thoughts:
1) Don't put a comma between the command-line options (just separate them with spaces).
2) With pxelinux, it can be helpful to use an append
line. For example:
append initrd=f16-x86_64/initrd.img ks=nfs:server.example.com:/path/to/f16.ks mycustomflag mykey=myval
3) Network settings (like the hostname example you gave) are often better served by DHCP.
I was able to get it working using the following commands to parse all of the key value pairs into variables:
# Get the kernel parameters
params=`cat /proc/cmdline`
# Split them on spaces
params_split=(${params// / })
# Go through each of them
for p in "${params_split[@]}"; do
# And if it's a key value pair
if [[ $p =~ "=" ]]; then
# And if the key doesn't have a period in it
p_split=(${p//=/ })
if [[ !($p_split[0] =~ ".") ]]; then
# Then set the key to the value
eval $p;
fi;
fi
done