Learning Puppet: Part 1

Puppet is a very useful configuration management tool that has become popular due to its ability to allow administrators to enforce configuration on an entire network. Here is an excerpt from the book Learning Puppet by Jussi Heinonen about why you should use Puppet instead of custom scripts:

Prior to Puppet, I used to use various self-written scripts to automate the deployment processes in order to make the process repeatable, but I’m doing much less of that since I discovered Puppet. The problem with scripts, as I see it, is that they are hard to transfer across and to hand over, as scripts are often complex and difficult to read by people who are unfamiliar with the language in which the scripts are written.

This book provided a lot of help for me and most of the examples are taken right from this book as I found they made it easier for me to get a hang of the basics.

The first step to learning Puppet is downloading the “Learning VM” from here. Once you have the image downloaded, extract the zip and boot up the VM (exact instructions depend on which virtualization software you use). If you are using KVM you may want to consider using qemu-img to convert the vmdk file to a qcow2 file using the following command:
[code language=”bash”]
user# qemu-img convert learn_puppet_centos-6.5-disk1.vmdk -O qcow2 puppet.qcow2
[/code]

Once you have the VM booted up you should see a login prompt, the default login credentials are ‘root’ with password ‘puppet’. Once you log in there should be a prompt like this:

Next you should check the version of Puppet that you are using to make sure it is not too old/new for this guide. At the time of writing this is the support version:
[code language=”bash”]
[root@learning ~]# puppet — version
3.7.3 (Puppet Enterprise 3.7.1)
[/code]

The way that puppet differentiates between different types of configurations (users, services, etc.) is through the use of resources. There are several built in resources but you can also create your own if you so desire. To see a complete list of the resources run the following command:
[code language=”bash”]
[root@learning ~]# puppet describe — list | less
[/code]

To get more information about a certain resource (zfs in this case):
[code language=”bash”]
[root@learning ~]# puppet describe zfs | less
[/code]

To manage Puppet resources you must use the puppet resource command. This command can be used on different resource types to enforce certain attributes on instances of a resource. For example we can force the creation of a user with the following command (Note that the password must be provided in a hashed form and not as plaintext, in this case the password is ‘puppet’):
[code language=”bash”]
[root@learning ~]# puppet resource user Ballard ensure=present managehome=true password=’$1$jrm5tnjw$h8JJ9mCZLmJvIxvDLjw1M/’
Notice: /User[Ballard]/ensure: created
user { ‘Ballard’:
 ensure => ‘present’,
 password => ‘$1$jrm5tnjw$h8JJ9mCZLmJvIxvDLjw1M/’,
}
[/code]

You may be wondering what exactly Puppet spits out when you run this command so lets walk through this.

  1. Notice: /User[Ballard]/ensure: created
  2. user { ‘Ballard’:
     ensure => ‘present’,
     password => ‘$1$jrm5tnjw$h8JJ9mCZLmJvIxvDLjw1M/’,
    }

If you log out of the machine and try to login with the user Ballard and password puppet it should work. While this is neat, it is not very scalable because we have to remember all the parameters every time we want to create a resource. Fortunately Puppet provides a way for us to define a resource in a file, and then have Puppet enforce configuration based on the attributes defined in that file.

To start lets create some new users using this file. Run the following commands:
[code language=”bash”]
[root@learning ~]# puppet resource user snax > users.pp
[root@learning ~]# puppet resource user glen >> users.pp
[root@learning ~]# cat users.pp 
user { ‘snax’:
 ensure => ‘absent’,
}
user { ‘glen’:
 ensure => ‘absent’,
}
[/code]

Note that this has not yet created the users for us, it has simply created a file that contains the instances of two user resources. To get Puppet to actually recognize these users we need to apply them using the puppet apply command. However before we do that we should take a closer look at the users.pp file and notice that ensure has been set to absent. If we leave the setting like this Puppet will delete the user every time it is created to we need to change the value to present instead. Your file should look like so:
[code language=”bash”]
[root@learning ~]# cat users.pp 
user { ‘snax’:
 ensure => ‘present’,
}
user { ‘glen’:
 ensure => ‘present’,
}
[/code]

Now we can apply the resources using puppet apply:
[code language=”bash”]
[root@learning ~]# puppet apply users.pp 
Notice: Compiled catalog for learning.puppetlabs.vm in environment production in 0.14 seconds
Notice: /Stage[main]/Main/User[snax]/ensure: created
Notice: /Stage[main]/Main/User[glen]/ensure: created
Notice: Finished catalog run in 4.25 seconds
[/code]

We can see Puppet claims to have created the users and if we check /etc/passwd file we can see it did work!
[code language=”bash”]
[root@learning ~]# grep -E “(snax|glen)” /etc/passwd
snax:x:507:507::/home/snax:/bin/bash
glen:x:508:508::/home/glen:/bin/bash
[/code]

That is all for an intro to Puppet, it should give a basic understanding of how Puppet can enforce configuration on a local machine. In later posts I hope to go over how to enforce settings for services as well as across various machines.