Narrator: We've already been
using Puppet's configuration language a little bit,
but now we're now going to go into it more more deeply.
Like most programming languages,
the Puppet language includes support
for variables, data types, conditional statements,
parameters and so on.
To see how these work in Puppet,
we're going to build our own module
for configuring the Etsy MOTD file
rather than using the one provided by Puppet labs.
Suppose that you have a mixture
of Red Hat and Ubuntu servers in your network,
and you always forget which Linux distribution
calls the Apache service Apache 2,
and which one calls it httpd.
To make things easier,
you decide to put a reminder
in the message of the day file on each server.
So on a Red Hat server, the MOTD file
would say that the Apache service
is called httpd.
And on an Ubuntu server it would say Apache 2.
Okay.
I admit that this probably isn't
how you would use Puppet in the real world.
But this exercise does have the advantage
of using a simple configuration file
that you can write from scratch,
while still having enough to it
to demonstrate many aspects of the Puppet language.
Once you've learned how to do this exercise,
and the template exercises in the following lessons,
then you'll be able to apply this knowledge
to doing things like configuring Apache itself.
Okay.
Back to the task at hand.
First, we need to build a directory tree for our module.
So go into the modules directory,
and use Puppet module generate.
Don't forget the skip interview parameter.
Let's call the module MOTD Apache.
Remember that we need to include the author's name
and a dash before the module name.
We'll just use test as the author again.
The first thing we're going to do
is write some code that figures out
which operating system is running on a server
so we know which message to put in the MOTD file.
Luckily, Puppet makes this very easy
because it generates a list of facts
about each node before running your code.
The program that does this is called Facter,
note that it is spelled with an er rather than an or.
You can see the facts that Facter generates
just by running it at the command line.
We'll pipe it to more
because it generates a very long list of facts.
You can see that it lists things
like the disks that are on the node.
We're not going to go through these here
because it's much easier to see
what facts are available
by looking at Puppet's online documentation.
Although there are a lot of facts on this page,
most of them are actually legacy facts
that you probably won't need to use.
Just look at the modern facts for now.
As of this moment, there are only 37 facts,
and you probably won't even use most of these.
The disrelatively small list is deceptive
because each one of these facts
contains numerous elements.
The fact we need right now is OS.
If you click on that,
you'll see that it has a ton of elements within it.
The obvious one to use to identify
a nodes operating system
is the name element.
However, it would be better to use the family element
just in case our code runs on a node
that isn't on either Red Hat or Ubuntu.
For example, if a node is running CentOS,
then it will follow the same conventions as Red Hat,
or if a node is running Debian,
it will use the same conventions as Ubuntu.
Now that we know which fact to use,
let's edit the init.pp manifest.
First, we're going to set a variable
to the OS family of the node it's running on.
Creating a variable in Puppet is very simple,
you just put a dollar sign in front of a name.
Then you put an equal sign
and what you want to set it to.
We'll call our variable OS family
and set it to the family element of the OS fact.
There are two ways to refer to a fact.
You can either refer to it
with the regular variable notation,
so in this case it would be $os
and then family in square brackets
because family is an element of the OS variable,
and we have to use a ray notation for that.
Or you can refer to it with the dollar facts variable name,
so in this case it would be $facts
and then os in square brackets
and then family in square brackets.
Although the first way is simpler,
I recommend that you use the second way
because that will make it very clear
that you're referencing a built in fact
rather than a variable that was set somewhere else.
Oh, and one more thing.
Puppet variables are actually constants
because you can't reassign them
after you've set their value.
But people call them variables anyway.
Alright, so we have our first line of code.
Next we're going to use an if statement
so we can run different code depending
on which OS family is on the node.
Puppet's if statement syntax is similar
to how it is in most other languages,
but especially Ruby.
After the if, you put the conditional expression.
We'll start with the OS family variable
and then we need to use a comparison operator.
Here are all of the comparison operators in Puppet.
The one we need is the equality operator
which is two equal signs.
After the equality operator,
we need to put the name of the OS family in quotes.
In the case of Ubuntu, it's Debian.
Then we put in the opening curly brace.
Now we'll set a variable to the string
we want to put in the MOTD file
for a Debian based OS.
Let's call the variable MOTD_content.
Finally, we put in the closing curly brace.
Now we need to put in an else statement.
If we want to say that all OS families
other than Debian or Red Hat,
then a simple else will do.
But we shouldn't do that in case this code runs
on a node with a different OS family.
So let's use an else if.
In Puppet, like in Ruby,
the else if command is spelled elsif.
Then we put the conditional expression
to test for a Red Hat family
and finish with an opening curly brace.
Now we set the MOTD_content variable
for the Red Hat family.
Now we put in a closing brace
and then we need a catch all
for all other OS families,
so we'll use else and an opening brace.
We'll set the MOTD_content for unknown OS's,
and finish with a final closing brace.
Now that the MOTD_content variable is set,
we need to put it in the MOTD file.
We've already covered how to do this
so I'll just add the code.
Let's try it out.
Now we'll see what's in the MOTD file.
Considering that we're running on an Ubuntu system,
it is correct in saying that the Apache service name
is Apache 2.
Although this code works,
frankly it's a little bit messy and hard to read.
Let's see what other conditionals
are available in Puppet.
An unless statement is sort of like the reverse
of an if statement, so that won't work.
A case statement would be a good choice for this,
but a selector would be even better.
A selector is similar to a case statement,
but it returns a value instead of executing code.
Let's edit init.pp again.
I'll just put the converted code in
so you can see what it looks like.
That looks much nicer doesn't it?
The selector is a very handy tool in Puppet
because there are many times
when you want to set a variable
to one of a set of potential values
based on a particular fact.
Also notice that since I just set the service variable
instead of the entire message
that will go in the MOTD file,
I had to change how the content attribute is set.
This is an example of how you can put a variable
inside a string.
As long as you put double quotes around the string,
then you can put a variable inside the string
and it's value will be put in its place.
Note that I used curly braces around the variable name.
In this case it would work
even if I didn't put the braces in
because the back slash N after service
is clearly not part of the variable name.
But it's a good idea to get in the habit
of putting the braces in
because they are often necessary.
When we do another Puppet run with the new code,
Puppet doesn't change anything
because the new code does exactly the same thing
as the old code did.
And that's it for this lesson.