creating a Debian GNU/Linux Wheezy puppet client for OpenStack

A Debian GNU/Linux wheezy image is booted and modified to set its hostname based on the content of the http://169.254.169.254/latest/meta-data/hostname metadata. The /etc/rc.local file is changed to run puppet agent –waitforcert 60 at boot time. The instance is then snapshoted and the corresponding file system reduced to a minimal size with resize2fs -M.

setting the hostname

When a new instance is created with

nova boot ... puppet-instance

the puppet-instance.novalocal fully qualified domain name is made available to the instance from the metadata service provided by OpenStack. It can be retrieved from the http://169.254.169.254/latest/meta-data/hostname URL. The /etc/rc.local file is modified to set the hostname as follows:

hostname=$(wget -q -O - http://169.254.169.254/latest/meta-data/hostname)
hostname $hostname
echo $hostname > /etc/hostname

The novalocal domain name is appended to the instance name and is defined by the dhcp_domain=novalocal option in the /etc/nova/nova.conf file. It can be set differently on each compute node, although this is likely to lead to confusion.

running as a puppet client

The /etc/nova/nova.conf is modified to include

puppet agent -vt agent --waitforcert 60

and the /etc/puppet/puppet.conf is modified to append the following:

[agent]
pluginsync=true

When the instance boots, it will try to connect to the puppet.novalocal puppet master. The puppet.novalocal hostname is inferred from the hostname of the instance because it was not explicitly set with the server=puppet.novalocal line of /etc/puppet/puppet.conf.
The –waitforcert 60 forces the client to wait for the puppet master to accept its request to join. This can either happen automatically if the puppet master is set to accept any client, or manually with

puppetca sign instancename.novalocal

on the puppet master.
The output of the puppet agent can be read from the instance console log with

# nova console-log instancename
...
[....] Starting OpenBSD Secure Shell server: sshd ok .
info: Creating a new SSL key for pp.novalocal
merr: Could not request certificate: getaddrinfo: Name or service not known

The output displayed above indicates that the puppet.novalocal name does not resolve. There is no default puppet master to query yet but the instance will try again when rebooted.

creating a minimal image

When the puppet image is ready, it is snapshoted with

nova image-create puppet-instance puppet

where the puppet-instance is the name of the instance in which the preparations occured and puppet will be the name of the bootable image created from it, as shown below:

# nova image-list
+--------------------------------------+-------------------------------+--------+--------------------------------------+
|                  ID                  |              Name             | Status |                Server                |
+--------------------------------------+-------------------------------+--------+--------------------------------------+
...
| 6465a3a1-bc1e-48db-84a7-b78a3976c609 | puppet | ACTIVE | 616e3a7c-c269-496e-b227-14330f77e502 |
...

The resulting image will have a size that is larger than necessary. For instance if the puppet instance had a root disk of 10GB, the image will have a size of 10GB. This can be an inconvenience because each OpenStack node will have to retrieve 10GB from the glance image server each time a puppet node needs to be booted. If the image is an AMI containing an ext4 file system, it can be reduced to a minimal size with:

fsck.ext4 -f /var/lib/glance/images/6465a3a1-bc1e-48db-84a7-b78a3976c609
resize2fs -M /var/lib/glance/images/6465a3a1-bc1e-48db-84a7-b78a3976c609

Note that the 6465a3a1-bc1e-48db-84a7-b78a3976c609 file name matches the id of the image displayed by the nova image-list command above. The machine on which these files reside is the one running the glance image service.

# ls -lh /var/lib/glance/images/6465a3a1-bc1e-48db-84a7-b78a3976c609
-rw-r--r-- 1 glance glance 910M Nov 19 01:11 /var/lib/glance/images/6465a3a1-bc1e-48db-84a7-b78a3976c609

running a puppet client instance from the commandline

Creating a new image may be overkill if the puppet client instance is only used a few times. An alternative is to add (inject) two files using the virgin Debian GNU/Linux instance –file of nova boot.
On the machine from which the nova boot command will be run, the puppet.conf and rc.local file are created.

cat > /tmp/puppet.conf <<EOF
[main]
logdir=/var/log/puppet
vardir=/var/lib/puppet
ssldir=/var/lib/puppet/ssl
rundir=/var/run/puppet
factpath=$vardir/lib/facter
templatedir=$confdir/templates
prerun_command=/etc/puppet/etckeeper-commit-pre
postrun_command=/etc/puppet/etckeeper-commit-post

[master]
# These are needed when the puppetmaster is run by passenger
# and can safely be removed if webrick is used.
ssl_client_header = SSL_CLIENT_S_DN
ssl_client_verify_header = SSL_CLIENT_VERIFY

[agent]
pluginsync=true
EOF

The content of the puppet.conf file comes from the puppet package, up to the [agent] section.

cat > /tmp/rc.local <<EOF
#!/bin/bash
hostname=$(wget -q -O - http://169.254.169.254/latest/meta-data/hostname)
hostname $hostname
echo $hostname > /etc/hostname
apt-get install -y puppet
puppet agent -vt agent --waitforcert 60
exit 0
EOF

which is identical to what was described above, except for the installation of the puppet client package.
Assuming a Debian GNU/Linux image by the name of wheezy is available, it can be turned into a puppet client with:

nova boot --image 'wheezy' --flavor e.1-cpu.10GB-disk.1GB-ram --key_name loic \
  --file /etc/rc.local=/tmp/rc.local --file /etc/puppet/puppet.conf=/tmp/puppet.conf \
  mypuppetclient

There is no way to set the execution bit on the /etc/rc.local file but this is not necessary because the content of /tmp/rc.local is written to /etc/rc.local using the tee command which leaves the original permissions untouched. It could however be a problem if creating a new file for which setting different permissions was necessary : the permissions of the /tmp/rc.local are not copied to the instance, only its content.