Dec 222006

As part of a vertical consolidation and virtualization project, I had set up a Kickstart configuration in order to boot x86 servers and install the VMWare ESX Server software. While I wrote this document specifically for ESX installations, the underlying OS was a modified Redhat 7.x distro (or something that seemed awfully similar). So here are the steps to implement and use a PXEBooting Kickstart environment.


  1. Linux server (can use a manually built ESX server for this purpose) with dhcpd (dhcp daemon), tftpd (tftp daemon) and nfs server services turned on.
  2. Have the dump of the ESX installation media CD in a directory/filesystem large enough to hold it.
mount /dev/cdrom /mnt

mkdir –p /images/install

cp –pra /mnt/* /images/install

umount /mnt

cd /images/ install/images

mount –o loop ./bootnet.img /mnt

cd /mnt

mkdir –p /tftpboot/pxelinux.cfg

cp boot.msg initrd.img syslinux.cfg vmlinuz /tftpboot

cd /tftpboot

umount /mnt

cp syslinux.cfg pxelinux.cfg/default


  • Having copied these files over, now make a copy of the /tftpboot/pxelinux.cfg/default to /tftpboot/pxelinux.cfg/bootnet
  • Edit /tftpboot/pxelinux.cfg/bootnet to make it look like this:

default ks
prompt 0
timeout 0
display boot.msg
F1 boot.msg
label linux
kernel vmlinuz
append initrd=initrd.img
label ks
kernel vmlinuz
append apic ks=nfs: ramdisk_size=10240 initrd=initrd.img

NOTE: Make sure that there isn’t actually a line break in the line starting with append (the entries following the “append” directive need to be on the same line and “\” has been put in for ease of readability only).

  • Get a copy of the “syslinux” distribution (run the commands listed below):

Explode the tarball like this:

# cp syslinux-3.07.tar.gz /tmp
# tar zxvf /tmp/syslinux-3.07.tar.gz
# cd /tmp/syslinux-3.07
# cp syslinux.0 /tftpboot

  • Edit the dhcp configuration file like this:

# vi /etc/dhcpd.conf

# ddns-update-style none;
ignore client-updates;
allow bootp;
allow booting;
option ip-forwarding false;
option mask-supplier false;
get-lease-hostnames off;
use-host-decl-names off;
option routers;

subnet netmask {
default-lease-time 1800;
max-lease-time 3600;
option subnet-mask;

host hostA {
hardware ethernet 00:AA:BB:CC:DD:EE;
#option option-214 “0AA5D6A4″;
filename “/tftpboot/pxelinux.0″;

NOTE: Choose the correct subnet (that your servers will reside in).

  • Make sure that the tftpd daemon is installed and edit the file /etc/xinetd.d/tftp to look like this:

service tftp
socket_type = dgram
protocol = udp
wait = yes
user = root
server = /usr/sbin/in.tftpd
server_args = /tftpboot
disable = no
per_source = 11
cps = 100 2

  • It is to be noted that the default ESX server install comes with gcc (2.96) and make (GNU Make version 3.79.1). But the tftp daemon and the dhcp daemon (server-side) aren’t installed by default.
  • Download the latest versions of the dhcp sources (can obtain the software by following instructions at this url: and build it by following the instructions in the README file or INSTALL file of the distribution (usually it is a standard method of ./configure; make; make install)
  • Similarly, obtain a copy of the latest tftp source from ( Following the build instructions will result in the installation of the tftpd binary on the system.
  • Start the dhcp daemon by running:

dhcpd -cf /etc/dhcpd.conf

  • Start the tftp daemon by sending a SIGHUP to the xinetd daemon

kill -HUP `ps -ef|grep xinetd|grep -v grep|awk ‘{print $2}’`

  • The NFS server services need to be started up after creating the appropriate NFS shares in /etc/exports. The contents of the /etc/exports file should look like this:

/vmimages/install *(ro,no_root_squash)
/vmimages/kickstart *(ro,no_root_squash)
/tftpboot *(ro,no_root_squash)

  • Start NFS services by running the following commands:

# cd /etc/rc.d/init.d
# ./portmap start
# ./nfs start
# ./nfslock start

  • After ensuring that the target ESX server (hardware) is plugged into the right subnet, boot the server and choose the PXE boot option. The booting from the PXE Ethernet ROM happens like this:

  1. Server boots and the PXE ROM loads, tries to acquire an IP address from the DHCP server (bootp).
  2. Once the IP address is obtained, the pxelinux.0 binary loads and obtains the vmlinuz kernel image via tftp.
  3. The initial ramdisk image (initrd, also acquired via tftp) is loaded into memory (to create the root filesystem in RAM).
  4. The kickstart configuration (ks.cfg) is acquired via NFS and used by the installer to do the “hands-free” installation.

Using the script

#!/usr/bin/perl -w

# Version: 1.2 (SCCS)

use File::Copy;

use Getopt::Std;

my %Args;
my $dhcp_config = “/etc/dhcpd.conf”;
my $null = “/dev/null”;
my $tftpdir = “/tftpboot”;
my $pxedir = “$tftpdir/pxelinux.cfg”;
my $netboot_cfg = “$pxedir/netboot.1″;

# Main

getopts( “m:s:i:h”, \%Args );

if ($Args{h}) {
printUsage() && exit 0;

$mac = $Args{m} || printUsage() && die “Unable to continue without a mac address \n”;

$hostname = $Args{s} || printUsage() && die “Unable to continue without a server name \n”;

$ip = $Args{i} || printUsage() && die “Unable to continue without an IP address \n”;

copy(“$dhcp_config”, “$dhcp_config.$$”) or die “Unable to backup $dhcp_config: $! n”;

open(DHCP, “>> $dhcp_config”) or die “Unable to write to $dhcp_config : $! \n”;

print DHCP “\n”;
print DHCP “host $hostname\{ \n”;
print DHCP “hardware ethernet $mac; \n”;
print DHCP “fixed-address $ip; \n”;
print DHCP “filename \”$tftpdir/pxelinux.0\”; \n”;
print DHCP “\} \n”;

print “Killing dhcp daemon…\n”;
system(“/usr/bin/pkill dhcpd”);
print “Starting dhcp daemon….\n”;
$start_cmd = “/usr/sbin/dhcpd -cf $dhcp_config”;

sub printUsage {
print “Correct Usage: $0 -m \”\” -s -i \”\” | -h \n”;

Using the script (modify to your heart’s content) , one could set up the dhcpd entries (knowing well that our friendly vi editor isn’t necessarily the most user-friendly (especially to the UNIX un-initiates..)) rather quickly/easily.

Here’s how:

# chmod +x
# ./ –m “11:22:33:44:55:66” –s buildserver01 –i “”

Would set up entries in dhcpd.conf like this:

[root@ksserver bin]# ./ -m “11:22:33:44:55:66″ -s buildserver01 > -i “”
Killing dhcp daemon…
Starting dhcp daemon….
Internet Systems Consortium DHCP Server V3.0.1
Copyright 2004 Internet Systems Consortium.
All rights reserved.
For info, please visit
Wrote 0 deleted host decls to leases file.
Wrote 0 new dynamic host decls to leases file.
Wrote 0 leases to leases file.
Listening on LPF/eth0/00:11:0a:53:e8:98/
Sending on LPF/eth0/00:11:0a:53:e8:98/
Sending on Socket/fallback/fallback-net

Take a look at the /etc/dhcpd.conf file later:

[root@ksserver bin]# tail /etc/dhcpd.conf
hardware ethernet 00:11:AA:BB:CC:DD;
filename “/tftpboot/pxelinux.0″;

host buildserver01{
hardware ethernet 11:22:33:44:55:66;
filename “/tftpboot/pxelinux.0″;

 Posted by at 7:50 pm
Dec 192006

An insightful member of the slashdot community had made this observation here ( Thought I’d spin it off and blog it.


  1. The power of perl is irrefutable — it helps slap together quick and clean solutions to irritating admin problems. The flip-side of being a perl jockey I guess is that one tends to try and create a solution to many a problem that already has a solution – because searching CPAN can be a pain at times.
  2. Use of the more flexible features of the languages (such as Hashes, hash of hashes etc) data/number munging and organization becomes more manageable.
  3. Using Perl’s almost endless modules, a lot of relatively complicated tasks can be simplified.
  4. Annoyance factor of numerous tasks (especially Administrative and reporting) can be reduced drastically with the help of Perl.


  1. The beef I guess is that unlike Python or Perl’s other competitors, Perl modules don’t come tightly integrated with the core distro. Agreed that Perl probably has a lot more modules than any of those other languages do, but a larger than ordinary de facto distribution (why not include important modules like Digest::MD5, Crypt modules, SSH modules etc?) would be desirable (especially in those situations where you don’t have access to the internet directly from within corporate networks and can’t install the modules with the “perl -MCPAN -e shell” option) . There might be those Perl veterans who would say — “build your own distro with your custom modules already packaged” — and while that might be a very smart thing to do, many a time (when one keeps moving from one environment to another — some call it job hopping, it helps to be able to download one single perl distro package or rpm or the source+compile and have basic administrative scripts work — especially those that rely on centralized automation (ssh-based trusts, copies across the network, etc).
  2. Also, perl’s syntax can be terse and difficult for noobies to understand (or even older perl-hands for that matter — when someone has written code without appropriate comments, etc).
  3. Tinkering with Python recently, I found it’s simplicity refreshing and it’s syntax easier to comprehend (especially when compared with Perl’s (imho) complicated “scoping” requirements, etc).
  4. Sometimes (and I guess it depends on the person writing the code) Perl tends to over-complicate things that can be easily handled via Shell scripts.

That much said (several months back), I’d have to say (after having written a pretty big (by my standards) application in Python, I like certain aspects of Python a lot (comprehensibility of code lists at the top) but I still found myself wanting to revert back to Perl at the slightest opportunity. I was irritated with the way you have to declare the variable type in Python (eg: can’t do a floating point operation on two numbers unless you qualify the variable as type float whereas in Perl it is automatically detected) — now I know there are those who will say “Perl does it wrong” and while that might be true, it is also true that a pressed-for-time Systems Admin could do with worrying about other things in the larger scheme of things…

I guess I must’ve have internalized the terse syntactical idiosyncrasies of Perl somewhere along the way and thinking in “Python” seemed a wee bit alien.

What I did like about Python is the ease with which one could develop GUI interfaces .
I actually had to write a reporting tool on the windows platform — and using the win32com.client module, coding was a piece of cake. I also played with the Tkinter module on UNIX and coding with it was a breeze as well.

 Posted by at 8:53 pm
Dec 192006

While this might be totally redundant, I couldn’t for the love of God remember how range operators were used within the various shells (and specifically the Korn shell). Tried various tricks but I guess I must’ve gotten “perl-ized” somewhere along the way. So here’s my workaround for quick shell scripts (usually fired off from the command line on the fly) that require range operators (say you want to iterate through the numbers 1 – 100 and do some activity with each value.

for i in `perl -e ‘foreach $i (1..100) { print “$i \n”; }’`
echo “I is $i”;

Here we’ll invoke a perl one-liner to print out the values of $i in the range 1 to 100. We read that and do something with it within a “ksh for loop”. It’s easier than having to type in:

for i in 1 2 3 4 5 …. 100
echo “I is $i”

Sidenote: Hopefully I’ll get to update this blog more often that I usually do — if there’s no one watching, at least it’s something for me to refer to (as a cheatsheet on the fly).

 Posted by at 8:28 pm