Dynamic RedHat Kickstarts With PHP

I have been preoccupied with the automation of a RedHat Linux install, from the PXEBoot process to release to production mode. As a budding sysadmin in an HPC environment, that means many machines to install. The more I can get software to do, the better.

On that note, I realized the future of provisioning Linux systems en masse was to abandon the concept of one kickstart file per system type. Why can’t I just dynamically generate them based on what each host is hardware-wise and also what the machine is supposed to do? Well, I did just that. The magic lies in the fact that the RedHat installer environment allows for a kickstart file to be downloaded via HTTP. All I need to do is to write a PHP script that spits out a custom kickstart file based on the connecting IP address:

<?php
include("config.php");
mysql_connect("host", "user", "password") or die(mysql_error());
mysql_select_db("database") or die(mysql_error());
$server = (empty($_GET['addr'])) ? $_SERVER['REMOTE_ADDR'] : $_GET['addr'];

$result = mysql_query("SELECT system_type, service_type FROM sys_inventory WHERE ip = '$server'") or die(mysql_error());
$row = mysql_fetch_array($result);
$system = $row['system_type'];
$service = $row['service_type'];
$packages = '';
$result = mysql_query("SELECT package from packages where service_type = 'global' or service_type = '$service'");

while ($row = mysql_fetch_array($result)) {
  $packages .= $row['package'] . "\n";
}

config_global();
config_system($system);
config_service($service);

echo"%packages --resolvedeps\n";
echo "$packages\n";
echo "%pre\n";
echo "cp /mnt/source/ks_scripts/pre.sh /\n";
echo "/pre.sh $system $service \n";

echo "\n";
echo "%post --nochroot\n";
echo "cp /mnt/source/ks_scripts/postnochroot.sh /mnt/sysimage/tmp/\n";
echo "cp /mnt/source/ks_scripts/post.sh /mnt/sysimage/tmp/\n";
echo "/mnt/sysimage/tmp/postnochroot.sh $system $service\n";
echo "\n";
echo "%post\n";
echo "/tmp/post.sh $system $service\n";
?>

You supply a config.php file to generate the global configs:

<?php

function config_global() {
  // Just echo the options that you want everybody to have, like root passwords, partitioning, whatever
}

function config_system($system) {
  if ($system == "dell") {
    // Maybe some special partitioning options?
  }
  
  if ($system == "sun") {
  
  }
}

function config_service($service){
  if ($service == "webserver") {        
  
  }

  if ($service == "mailserver") {
  
  }
}

?>

Next, you shove shell scripts (pre.sh, postnochroot.sh, post.sh in a directory that the installer can access, like a NFS mount:

#!/bin/sh
# %PRE section script

SYSTEM=$1
SERVICE=$2

# Put your global stuff here
# Define unique system-oriented procedures

case $SYSTEM in
  dell)
    # Do stuff
  ;;

  sun)
  
  ;;

  *)
    echo "System type not recognized. Is it in the database?";
  ;;
esac

# Define unique service-oriented procedures

case $SERVICE in

  webserver)
  ;;

  mailserver)
  ;;

  *)
    echo "Service type not recognized. Is it in the database?";
  ;;
esac

Now, you just need a MySQL database that at least stores the ip, the system type, and the service type, and you’ll be on your way to a fully-automated Linux server setup! I’ll document this in more detail and release the sourcecode and documentation in a better format than a blog post, but at least you can play with it now!

Kickstart docs: here