In our environment, we have:
centralized DHCP, DNS
80+ sites
each site has its own subnet
each subnet has a PXE setting for an IP reservation for one universal MAC address
we have 17 desktop and 4 mobile FOG servers
What I’ve built and will slowly deploy over what we currently have is:
Windows Server 2012 R2 Update 1 or Windows 8.1 Update 1 running Hyper-V
Hyper V machine consists of 2 (mobile systems) or 3 (desktop systems) virtual HDD (.vhdx)
OS.vhdx (Debian8 + Fog), two storage nodes: images.vhdx (DefaultMember/images), the optional other.vhdx (other/images)
A script is called as a job from rc.local to run at every powerup of the VM.
This script contains a while/do/done to wait for an IP address. Why wait? If there was a power failure at a site, the server will be up long before the switches, and wouldn’t be able to reach our centralized DHCP. So it waits until …
Once an IP is found, it changes the IP used in 3 MySQL entries, the storage nodes and two files (.fogsettings, default.ipxe); then restarts tftpd-hpa, mysql, fog and apache2 services to recognize the new IP address.
Any one of these dynamic FOG servers can be powered up at any site and will work without intervention. Worst case, it needs to be rebooted once.
To put the icing on the cake, I have another small script that can be run by the administrator that will change the hostname at all levels in one go if desired.
Images are separated into mandatory Approved images (DefaultMember/images.vhdx) available for every site, and site-specific (other) images created centrally or by the site’s technician.
When I bundle up a new wave of Approved Images, I can replace the entire images.vhdx, update the VM pointers without affecting the site-specific .VHDX, and we’re good.
I can also centrally manage the host OS and Virtual Machines through Hyper-V Manager .
… but that’s our environment. 😎
The following meat and potatoes is all taken out of context (I do a lot more) but is in order from my FOG installation recipe.
This Code Paste destroys/recreates the rc.local file (sudo su first of course)
cp -f /etc/rc.local /etc/rc.local.old &&
echo '#!/bin/sh -e' > /etc/rc.local &&
echo '#' >> /etc/rc.local &&
echo '# rc.local' >> /etc/rc.local &&
echo '#' >> /etc/rc.local &&
echo '# This script is executed at the end of each multiuser runlevel.' >> /etc/rc.local &&
echo '# Make sure that the script will "exit 0" on success or any other' >> /etc/rc.local &&
echo '# value on error.' >> /etc/rc.local &&
echo '#' >> /etc/rc.local &&
echo '# In order to enable or disable this script just change the execution' >> /etc/rc.local &&
echo '# bits.' >> /etc/rc.local &&
echo '#' >> /etc/rc.local &&
echo '# By default this script does nothing.' >> /etc/rc.local &&
echo ' ' >> /etc/rc.local &&
echo 'make_fog_portable &' >> /etc/rc.local &&
echo ' ' >> /etc/rc.local &&
echo 'exit 0' >> /etc/rc.local &&
chmod 755 /etc/rc.local &&
Create the make_fog_portable job script called by rc.local
echo '#!/bin/bash' > /bin/make_fog_portable &&
echo '#' >> /bin/make_fog_portable &&
echo '# make_fog_portable &' >> /bin/make_fog_portable &&
echo '#' >> /bin/make_fog_portable &&
echo '# This script is expected to be run as a job from /etc/rc.local' >> /bin/make_fog_portable &&
echo '# It will wait until an IP address is found, then use that IP' >> /bin/make_fog_portable &&
echo '# address to configure the FOG Server for that site.' >> /bin/make_fog_portable &&
echo '#' >> /bin/make_fog_portable &&
echo ' ' >> /bin/make_fog_portable &&
echo 'exit 0' >> /bin/make_fog_portable &&
chmod 755 /bin/make_fog_portable &&
vim /bin/make_fog_portable
Then you paste this in before exit 0:
# Wait for an IP address
IP=`ip addr list eth0 | grep "inet " |cut -d" " -f6|cut -d/ -f1`
while [ -z $IP ]
do
echo "Waiting :30 for an IP Address" > /dev/kmsg
sleep 30
IP=`ip addr list eth0 | grep "inet " |cut -d" " -f6|cut -d/ -f1`
done
# Make FOG Server Portable
sleep 6
echo "Updating IP address for FOG_TFTP_HOST to be $IP [`date`]" > /dev/kmsg
mysql --user=root -p<password> -e "UPDATE \`globalSettings\` SET \`settingValue\` = '$IP' WHERE \`settingKey\` ='FOG_TFTP_HOST';" fog
echo "Updating IP address for FOG_WEB_HOST to be $IP [`date`]" > /dev/kmsg
mysql --user=root -p<password> -e "UPDATE \`globalSettings\` SET \`settingValue\` = '$IP' WHERE \`settingKey\` ='FOG_WEB_HOST';" fog
echo "Updating IP address for FOG_WOL_HOST to be $IP [`date`]" > /dev/kmsg
mysql --user=root -p<password> -e "UPDATE \`globalSettings\` SET \`settingValue\` = '$IP' WHERE \`settingKey\` ='FOG_WOL_HOST';" fog
echo "Updating IP address for Storage Node DefaultMember to be $IP [`date`]" > /dev/kmsg
mysql --user=root -p<password> -e "UPDATE \`nfsGroupMembers\` SET \`ngmHostname\` = '$IP' WHERE \`ngmMemberName\` ='DefaultMember';" fog
echo "Updating IP address for Storage Node other to be $IP [`date`]" > /dev/kmsg
mysql --user=root -p<password> -e "UPDATE \`nfsGroupMembers\` SET \`ngmHostname\` = '$IP' WHERE \`ngmMemberName\` ='other';" fog
echo "Updating IP address in file .fogsettings to be $IP [`date`]" > /dev/kmsg
sed -i "s;ipaddress=\".*\";ipaddress=\"$IP\";" /opt/fog/.fogsettings
echo "Updating IP address in file default.ipxe to be $IP [`date`]" > /dev/kmsg
sed -i "s;http://\([^/]\+\)/;http://$IP/;" /tftpboot/default.ipxe
sed -i "s;http:///;http://$IP/;" /tftpboot/default.ipxe
# Restart Critical FOG Services
echo "Restarting Critical FOG Services [`date`]" > /dev/kmsg
systemctl restart tftp* mysql* FOG* apache*
echo "Sleeping 30 seconds before releasing script [`date`]" > /dev/kmsg
sleep 30
echo "releasing script [`date`]" > /dev/kmsg
I also perform this on the OS:
cd /var/www/fog/lib/fog &&
cp -f Config.class.php Config.class.php.old &&
sed -i "s;\".*\..*\..*\..*\";\$_SERVER['SERVER_ADDR'];" Config.class.php
If it’s a Ubuntu system I would also do:
echo manual >> tee /etc/init/mysql.override