Portrait of Martijn

Creating Ubuntu Templates for CloudStack

30 Aug 2013

Now that I have the CloudStack infrastructure configured, the next question is how to create Ubuntu templates for the instances.

At first-boot, I want it to update the hostname based on cloud-stack provided meta-data, update /etc/hosts such that the hostname matches the LAN IP address, and re-generate ssh keys.

Recently, documentation was comitted on how to prepare Linux for templating. For a formatted version see the nightly build PDF, and look for section "12.10. Creating a Linux Template". On trying that, I ran into several issues with the sethostname script, and filed CLOUDSTACK-4556.

The documentation addresses the use-case of producing pristine VMs. For my internal purposes I want to retain the custom user created during the Ubuntu installation, and I've added a .ssh/authorized_keys for easy access, and set a root password.

sudo -i
apt-get update
apt-get upgrade -y
apt-get install -y acpid ntp
reboot

# "12.14. Adding Password Management to Your Templates"
wget -O /tmp/cloud-set-guest-password.in http://download.cloud.com/templates/4.2/bindir/cloud-set-guest-password.in && \
mv /tmp/cloud-set-guest-password.in /etc/init.d/cloud-set-guest-password && \
chmod +x /etc/init.d/cloud-set-guest-password

cat > /etc/dhcp/dhclient-exit-hooks.d/sethostname <<'EOM'
#!/bin/sh
# dhclient change hostname script for Ubuntu
# /etc/dhcp/dhclient-exit-hooks.d/sethostname
# logs in /var/log/upstart/network-interface-eth0.log

# for debugging:
echo "cloudstack-sethostname BEGIN"
export
set -x

if [ $reason = "BOUND" ]; then
    echo new_ip_address=$new_ip_address
    echo new_host_name=$new_host_name
    echo new_domain_name=$new_domain_name

    oldhostname=$(hostname -s)
    if [ $oldhostname != $new_host_name ]; then

        # Rename Host
        echo $new_host_name > /etc/hostname
        hostname -F /etc/hostname

        # Update /etc/hosts if needed
        TMPHOSTS=/etc/hosts.dhcp.new
        if ! grep "$new_ip_address $new_host_name.$new_domain_name $new_host_name" /etc/hosts; then
            # Remove the 127.0.1.1 put there by the debian installer
            grep -v '127\.0\.1\.1 ' < /etc/hosts > $TMPHOSTS
            # Add the our new ip address and name
            echo "$new_ip_address $new_host_name.$new_domain_name $new_host_name" >> $TMPHOSTS
            mv $TMPHOSTS /etc/hosts
        fi

        # Recreate SSH2 keys
        export DEBIAN_FRONTEND=noninteractive 
        dpkg-reconfigure openssh-server
    fi
fi
echo "cloudstack-sethostname END"
EOM
chmod 644 /etc/dhcp/dhclient-exit-hooks.d/sethostname

rm -f /etc/udev/rules.d/70*
rm -f /var/lib/dhcp/dhclient.*
rm -f /etc/ssh/*key*
if [ -f /var/log/audit/audit.log ]; then cat /dev/null > /var/log/audit/audit.log; fi
cat /dev/null > /var/log/wtmp 2>/dev/null
logrotate -f /etc/logrotate.conf 2>/dev/null
rm -f /var/log/*-* /var/log/*.gz 2>/dev/null
rm -f /var/log/upstart/*.log /var/log/upstart/*.log.*.gz

echo "localhost" > /etc/hostname
hostname -F /etc/hostname

history -c
unset HISTFILE

halt -p

then take a snapshot (Instances → your instance → View Volumes → root volume → Take Snapshot), and create a template from it (Storage → Snapshots → your snapshot → Create Template).

If you want to create a new Template based on a VM that was created from the above Template, then you need to repeat the rm commands and should reset the hostname, and manually remove the current hostname line from /etc/hosts.

Unfortunately you cannot increase the root volume size when creating an instance, so you may need to create multiple sizes of templates for different offerings; either be repeating multiple ISO installations to different sizes, or by hacking the disk image and database.