Puppet Language Essentials
The course is part of this learning path
Puppet is an IT automation system. If you need to install, configure, and update servers, then Puppet can help you tremendously. Instead of doing all of these tasks manually, you can tell Puppet to configure your servers for you.
Not only will Puppet free you from the drudgery of repetitive tasks, but you will also gain major benefits, such as consistency, reliability, speed of deployment, ease of recovery, and scalability.
Do you often have slightly different configurations on servers that are supposed to be identical? With Puppet, you’ll no longer have to figure out why something works on one server but doesn’t work on another one because Puppet will configure them in the same way. You’ll also have less downtime because there is less that can go wrong when everything is configured the way it’s supposed to be.
Do you always seem to be adding more servers? Provisioning servers is a breeze when Puppet already knows how to configure them.
This course will get you started on bringing these benefits to your network. It’s a hands-on course with exercises every step of the way to give you experience using Puppet. First, I will show you how to install Puppet on a virtual machine on your own desktop. Then you will use it as a test environment to learn how to write Puppet code to automate server configuration.
- Install Puppet server
- Use pre-built Puppet modules
- Use manifests, classes, resources, facts, nodes, and templates
- Create your own Puppet modules
Let's say that you want to set the contents of the /etc/motd file to "Hello world!" instead of the default content set by the motd module. To do that, we're going to create our own module that uses the motd module.
A module contains manifests, which are just files with Puppet code in them. Inside the manifests are a variety of elements, but the most important ones are classes. A class is a named block of Puppet code that can be applied when it is invoked by its name. A very simple module could contain just one manifest file with one class inside it. A more complex module could contain a whole hierarchy of manifests with numerous classes and even supporting libraries. In this motd example, we'll be creating a very simple module.
Before we create our own module, let's see what's in the motd module. The main modules directory for Puppet is here. Yes, that's a pretty long path name, but the directory is so deep because it's possible to have multiple modules directories for multiple environments, such as development and production. We're only using the production environment because this is just a test VM that's not hooked up to a real production environment.
Have a look at what's in the motd directory with the ls -R command, so we can see all of the subdirectories too. Wow, that's a lot of files. To make it a bit easier to read, I like to use the tree command which, unfortunately, isn't installed by default on Ubuntu, but it's very easy to install, so let's do that. Now just type tree motd. That's a lot nicer, isn't it?
This is a much more complex module than we're going to create, so I won't go into a lot of detail about it. But note that the heart of the module is the manifests directory, which only contains one manifest called init.pp. By the way, all Puppet manifests have the extension pp. The biggest directories are spec and tests, which are both related to testing the module's code, rather than containing module code themselves.
To create our own module, we need to create a directory structure like this, although quite a bit simpler. Thankfully, Puppet provides a nice tool for doing that called puppet module generate. We're just going to add one option to it called --skip-interview. If you don't include that option, then it will ask you a whole bunch of questions to fill in the metadata for the module. We're going to skip that.
Then we just tell it the name of the module we're creating. The name needs to be two words with a hyphen in between, just like puppetlabs-motd. The first word is the author and the second is the name of the module. For an author name, I'm just going to use test for now because I'm not planning on publishing this module on the forge. For the module name, we can't call it motd because that's already taken. So let's call it motdsetup. Makes sure you're still in the modules directory before you run this command, because it will create the module in your current directory.
Let's have a look at what it created using the tree command again. There are still quite a few files and directories, but it's much simpler than what we saw in the motd module. Even so, we're going to ignore everything in here except for two files, both of them named init.pp.
First we'll edit the init.pp file in the manifest directory because this is the main manifest file in a module. There is a large comment section in here that you would fill in to document your module, but we're going to leave that alone. If you scroll down, you'll see that, after the comment section, there is the beginning of a class definition for motdsetup. That's because the name of the class in the init.pp manifest has to be the same as the name of the module.
By the way, you might be wondering what language Puppet uses. Well, Puppet has its own language, although it was inspired by the Nagios configuration file format. It's very similar to many other languages though, so it's pretty easy to learn.
Now we just need to add some code to use the puppetlabs-motd module and to set the contents of the motd file to Hello World. The way we do that is through a class declaration. This is different from a class definition, which is kind of confusing. Let's put in the code to declare the motd class, and then I'll explain definitions versus declarations.
If you look in the example section in the comments above, it shows an example of declaring a class. First you type class, and then a curvy brace. Then you type the name of the class you want to use surrounded by single quotes and follow it with a colon. In this case, we want to use motd, which is the main class of the motd module. Don't type motdsetup like they show in the example, because that's the name of the class we're creating, not the name of the puppetlabs-motd module's class.
On the next line, you specify a parameter that you want to set. In our case, we want to set the parameter that says what content to put in the /etc/motd file. The name of that parameter is content. How do I know that? Because it's in the documentation for the motd module. Hey, did you notice that the documentation also gives us an example of how to set the content parameter? Coincidentally, that's exactly what we need to accomplish our goal. So let's just copy this line.
We need to paste it here. After the content parameter, you use a hash rocket. I would just call it an arrow, but hash rocket sounds cooler, doesn't it? Then you put in the value we're setting the content parameter to, which in this case is "Hello World!" in double quotes. After that, you can put in a comma, which would be necessary if we were going to set more parameters, but since we're not going to do that, we don't need the comma. However, it's a common practice to put in a comma anyway, just in case you add another parameter later and you forget to add the comma at that time.
Now, we need to make one change to this. The /n should actually be a \n. \n is a special character that means new line. If we were to use /n, then it wouldn't be interpreted as a special character, and our Hello World message would have a messy looking /n at the end of it. So the moral of the story is, don't blindly trust everything that you read in a module's documentation.
Anyway, back to the task at hand. The final thing we need to do is add a closing curly brace on the next line.
Now I'll explain the difference between class definitions and declarations. When we define a class, we are saying what the class does when it is run. In this case, we are defining class motdsetup, and what it inside the curly braces is what this class does when you run it.
When we declare a class, that's when we're actually running it. In this case, we're running the motd class and giving it a parameter to use during that run.
The easy way to see whether a class is being defined or being declared is to look at where the class name is. When you're defining a class, you put the class name before the curly brace. When you're declaring a class, you put the class name after the curly brace.
Okay, now that we have that straight, let's save the file.
If you want to make sure that you don't have any syntax errors in your code, then you can run the Puppet parser like this, puppet parser validate init.pp. If everything is okay, then there won't be any output. This is a bit different from running puppet apply with the noop option, because the Puppet parser only checks the syntax. It doesn't tell you what would happen if Puppet were to run this code.
Just so you can see what it would say if you did have a syntax error, let's go back in and mess something up. Suppose we forgot to put quotes around Hello World. Let's remove them and see what happens. We'll run the Puppet parser again. Now it tells us we have a syntax error at World. It also tells us the line and column number where the error occurs, that is line 47, column 22.
Let's go back in and fix the error. If you're using vi, then you can type 47G, and it will take you to line 47. If we put our cursor over the W in World, then you'll see, at the bottom right, it shows that the line number is 47 and the column number is 22.
You might be wondering why it says the syntax error starts at World instead of at Hello. That's because the parser doesn't know that Hello World is supposed to be a string. It's just interpreting Hello and World as two separate values, and it knows you can't assign more than one value to a parameter. If you just put Hello in without any quotes, then the parser would not say there's an error. This is an example of how the parser can say that the syntax is okay, but the code will still not execute properly because, of course, code can technically have the correct syntax and still not do what you intended.
Okay, now we'll add the quotes back in and save the file. We'll run Puppet parser one more time just to make sure. There's no output, so it's all good again.
Now, you might think that we could run puppet apply to test out our code, but that actually wouldn't work. In our init.pp manifest, we just defined our motdsetup class. In order to run it, we need to declare it somewhere. So puppet apply would run without errors, but it wouldn't do anything.
Luckily, the puppet module generate command that we ran to create our module's directory structure also created a file that declares our motdsetup class. It's in a directory called examples. And it's also called init.pp. Let's have a look at what's inside.
You can see that, after a bunch of comments, it only has one real line of code. That line is include ::motdsetup. This is another way of declaring a class. You'll recall that when we declared the motd class in our motdsetup definition, we used class curly brace motd, which looked totally different from the line in this file. The reason we didn't use include to declare the motd class is because we also needed to set the content parameter. Here we just need to declare the class, and we don't need to set any parameters.
This is a much simpler syntax, but it's still a bit weird because it has two colons in front of the module name. The truth is that you don't need to use the two colons. In fact, you could remove them and everything would still work. In versions of Puppet before version four, it was sometimes necessary to put in the double colons due to a design problem, but that has been fixed in version four, so you don't need to do that anymore. However, there isn't any harm in leaving them there, so we won't bother editing this file.
Okay, so to test our motdsetup class, we need to run puppet apply on this file, which will declare the motdsetup class. By the way, you might get a warning message about the hiera.yaml file. If you do, then just ignore it.
It looks like it worked, but let's see what's in the /etc/motd file now, just to make sure. Excellent, and that's it for this lesson.
About the Author
Guy launched his first training website in 1995 and he's been helping people learn IT technologies ever since. He has been a sysadmin, instructor, sales engineer, IT manager, and entrepreneur. In his most recent venture, he founded and led a cloud-based training infrastructure company that provided virtual labs for some of the largest software vendors in the world. Guy’s passion is making complex technology easy to understand. His activities outside of work have included riding an elephant and skydiving (although not at the same time).