Managing Infrastructure with Puppet - James Loope [8]
* * *
Note
You can define client node names in the /etc/puppet/autosign.conf file in the format agenthost.example.com or even *.example.com. Names matching these patterns will be signed automatically by the master.
* * *
At this point, we should have a fully functional master and agent pair. The client certificate is signed, the node has a definition, and there is a class for the ntp installation assigned to it. Let’s prove that it works by running sudo puppetd --test --server puppet.example.com on our client. You should see the agent run through our manifest and install ntp.
Congratulations, you’ve taken a big step toward implementing a scalable configuration management architecture. Some deployments will need more complicated logic than packages and configuration files, but there are plenty of resource types, plug-ins, and examples to help you out. In the next chapter, we’ll look at the more advanced features of Puppet that will let you take these simple configuration definitions and apply them in a larger-scale fashion.
* * *
Puppet in the Ubuntu Cloud
If you’re using Ubuntu virtual images (on Amazon AWS or Ubuntu Enterprise Cloud), you will have a neat feature called cloud-init. Cloud-init provides a boot hook that can consume data from an input on instance launch and do things like install packages or execute scripts. On your instance there will be an example at /usr/share/doc/cloud-init/examples/cloud-config-puppet.txt that describes how to install Puppet at boot and contact a Puppet Master:
puppet:
conf:
agent:
server: "puppetmaster.example.com"
certname: "myinstance.example.com"
At the simplest, all that needs to be specified in this file is your Puppet server and the node name to identify the new instance (cert name).
* * *
Chapter 2. Puppeteering
Before we can get into a full-scale example, we need to add more tools to our Puppet workbench. Puppet provides several layers of abstraction to give you a variety of options for structuring configurations.
Defines
In this example, I’ve defined a type called yellifmissing, which takes a parameter $path. Then I can instantiate an instance of yellifmissing called pathnumber1 and pass the path parameter /tmp/filenumber1. Then I can do it again. Each of these resource declarations will email me about the specified missing file. Using a defined type, I can compartmentalize and duplicate blocks of logic, similar to an instance class in most object-oriented languages:
define yellifmissing ($path) {
exec { mailaboutit:
command => "echo 'OhNoes!' | mail -s '$name is missing' admin@example.com",
unless => "test -f $path",
}
}
yellifmissing { pathnumber1: path => '/tmp/filenumber1' }
yellifmissing { pathnumber2: path => '/tmp/filenumber2' }
Inheritance and Parameterized Classes
As we saw in the ntp example, classes are great for organizing our configurations, but they can also enhance the reusability of our code. Classes in Puppet, unlike define types, are not like their instanceable namesake in other object-oriented programming languages. They will take parameters and can even inherit structure from other classes, but only one class of a particular name can exist on