Beginnings are such delicate times. | ||
--Frank Herbert, 'Dune' |
In this chapter, you'll learn how to write your first manifest with Puppet, and how to put Puppet to work configuring a server. You'll also understand how Puppet compiles and applies a manifest. You'll see how to use Puppet to manage the contents of files, how to install packages, and how to control services.
The first example program in any programming language, by tradition, prints hello, world
. Although we can do that easily in Puppet, let's do something a little more ambitious, and have Puppet create a file on the server containing that text.
On your Vagrant box, run the following command:
sudo puppet apply /examples/file_hello.pp
Notice: Compiled catalog for ubuntu-xenial in environment production in 0.07 seconds
Notice: /Stage[main]/Main/File[/tmp/hello.txt]/ensure: defined content as '{md5}22c3683b094136c3398391ae71b20f04'
Notice: Applied catalog in 0.01 seconds
We can ignore the output from Puppet for the moment, but if all has gone well, we should be able to run the following command:
cat /tmp/hello.txt
hello, world
Let's look at the example code to see what's going on (run cat /example/file_hello.pp
, or open the file in a text editor):
file { '/tmp/hello.txt': ensure => file, content => "hello, world ", }
The code term file
begins a resource declaration for a file
resource. A resource is some bit of configuration that you want Puppet to manage: for example, a file, user account, or package. A resource declaration follows this pattern:
RESOURCE_TYPE { TITLE: ATTRIBUTE => VALUE, ... }
Resource declarations will make up almost all of your Puppet manifests, so it's important to understand exactly how they work:
RESOURCE_TYPE
indicates the type of resource you're declaring; in this case, it's a file
.TITLE
is the name that Puppet uses to identify the resource internally. Every resource must have a unique title. With file
resources, it's usual for this to be the full path to the file: in this case, /tmp/hello
.The remainder of this block of code is a list of attributes that describe how the resource should be configured. The attributes available depend on the type of the resource. For a file, you can set attributes such as content
, owner
, group
, and mode
, but one attribute that every resource supports is ensure
.
Again, the possible values for ensure
are specific to the type of resource. In this case, we use file
to indicate that we want a regular file, as opposed to a directory or symlink:
ensure => file,
Next, to put some text in the file, we specify the content
attribute:
content => "hello, world ",
The content
attribute sets the contents of a file to a string value you provide. Here, the contents of the file are declared to be hello, world
, followed by a newline character (in Puppet strings, we write the newline character as
).
Note that content
specifies the entire content of the file; the string you provide will replace anything already in the file, rather than be appended to it.
What happens if the file already exists when Puppet runs and it contains something else? Will Puppet change it?
sudo sh -c 'echo "goodbye, world" >/tmp/hello.txt' cat /tmp/hello.txt goodbye, world sudo puppet apply /examples/file_hello.pp cat /tmp/hello.txt hello, world
The answer is yes. If any attribute of the file, including its contents, doesn't match the manifest, Puppet will change it so that it does.
This can lead to some surprising results if you manually edit a file managed by Puppet. If you make changes to a file without also changing the Puppet manifest to match, Puppet will overwrite the file the next time it runs, and your changes will be lost.
So it's a good idea to add a comment to files that Puppet is managing: something like the following:
# This file is managed by Puppet - any manual edits will be lost
Add this to Puppet's copy of the file when you first deploy it, and it will remind you and others not to make manual changes.
Because you can't necessarily tell in advance what applying a Puppet manifest will change on the system, it's a good idea to do a dry run first. Adding the --noop
flag to puppet apply
will show you what Puppet would have done, without actually changing anything:
sudo sh -c 'echo "goodbye, world" >/tmp/hello.txt' sudo puppet apply --noop /examples/file_hello.pp Notice: Compiled catalog for ubuntu-xenial in environment production in 0.04 seconds Notice: /Stage[main]/Main/File[/tmp/hello.txt]/content: current_value {md5}7678..., should be {md5}22c3... (noop)
Puppet decides whether or not a file
resource needs updating, based on its MD5 hash sum. In the previous example, Puppet reports that the current value of the hash sum for /tmp/hello.txt
is 7678...
, whereas according to the manifest, it should be 22c3...
. Accordingly, the file will be changed on the next Puppet run.
If you want to see what change Puppet would actually make to the file, you can use the --show_diff
option:
sudo puppet apply --noop --show_diff /examples/file_hello.pp
Notice: Compiled catalog for ubuntu-xenial in environment production in 0.04 seconds
Notice: /Stage[main]/Main/File[/tmp/hello.txt]/content:
--- /tmp/hello.txt 2017-02-13 02:27:13.186261355 -0800
+++ /tmp/puppet-file20170213-3671-2yynjt 2017-02-13 02:30:26.561834755 -0800
@@ -1 +1 @@
-goodbye, world
+hello, world
These options are very useful when you want to make sure that your Puppet manifest will affect only the things you're expecting it to—or, sometimes, when you want to check if something has been changed outside Puppet without actually undoing the change.
Here's how your manifest is processed. First, Puppet reads the manifest and the list of resources it contains (in this case, there's just one resource), and compiles these into a catalog (an internal representation of the desired state of the node).
Puppet then works through the catalog, applying each resource in turn:
/tmp/hello.txt
should exist. The first time you run sudo puppet apply
, this won't be the case, so Puppet will create the file for you.content
. We've specified that the content of the file should be hello, world
. If the file is empty or contains something else, Puppet will overwrite the file with what the catalog says it should contain.In this case, the file will be empty the first time you apply the catalog, so Puppet will write the string hello, world
into it.
We'll go on to examine the file
resource in much more detail in later chapters.
Create your own manifest file (you can name it anything you like, so long as the file extension is .pp
). Use a file
resource to create a file on the server with any contents you like. Apply the manifest with Puppet and check that the file is created and contains the text you specified.
Edit the file directly and change the contents, then re-apply Puppet and check that it changes the file back to what the manifest says it should contain.
18.188.96.232