Book Image

LEARNING PUPPET

Book Image

LEARNING PUPPET

Overview of this book

Table of Contents (17 chapters)
Learning Puppet
Credits
About the Author
About the Reviewers
www.PacktPub.com
Preface
Index

Creating Puppet manifests


We covered the Puppet DSL syntax that is used in the Puppet manifests. Let's try to create a manifest and learn how to apply it to the system.

Note

The simplest way to create a manifest is to use the puppet resource command to create the resource definition and redirect the output of the command to the manifest file.

The following are the steps to create a manifest:

  1. Use the puppet resource command to declare a user resource and redirect the command output to a file using a single greater than character > followed by the filename:

    puppet resource user Jakob > user.pp
    

    This command won't return any message to the screen as you have redirected the command output to a file called user.pp.

  2. Before we inspect the contents of the user.pp file, let's add another user definition to user.pp with the following commands. This time, the output redirection is done using the double greater than characters >>. The difference between the single and the double greater than characters is how the output file is managed. The > character overwrites the file contents if the file already exists, while the >> characters append to the file:

    puppet resource user Markus >> user.pp
    
  3. Let's take a look at the content of the user.pp file. To view the content, we can open the file in the text editor. Linux systems usually come with multiple text editors, such as Vi, but we'll use another editor called Nano, which is easier to use than Vi.

  4. You can open the user.pp file in the Nano text editor by typing the following command:

    nano user.pp
    
  5. You will see that the user.pp file contains two user definitions: the first definition is for the user Jakob and the second definition is for the user Markus. Currently, both the resources have the ensure attribute value as absent, which corresponds to the current state of the user accounts on the system.

    Here is the content of the file in the Nano text editor:

    user { 'Jakob':
      ensure => 'absent',
    }
    user { 'Markus':
      ensure => 'absent',
    }
    
  6. Using the arrow keys on the keyboard, you can move the cursor around the text file. Change both the ensure attribute values to present.

  7. Once the ensure attribute values for both the user resources have been changed, the content of the file should be as follows:

    user { 'Jakob':
      ensure => 'present',
    }
    user { 'Markus':
      ensure => 'present',
    }
    
  8. Now press Ctrl + X on the keyboard and save the changes by pressing Y and then Enter.

    Well done! You have just created your first manifest file that manages two resources. Now it's time to apply the manifest with the following command:

    puppet apply user.pp
    

    The following is the output generated by the preceding command:

You must have probably noticed that this time we ran the puppet apply command without the -–execute option. The --execute option is only used to provide the manifest content from the command line. Now that we have created the manifest file, and if we want to apply it, the --execute option can be omitted. Typically, the --execute option is used to pass parameters to the Puppet class that is declared in the manifest. We will discuss the Puppet classes more in detail later on in this book.

Idempotency

Let's run the command again, and you will notice the difference in the command output compared to the previous Puppet run:

puppet apply user.pp

This time, the output is shorter. The lines that notify us that the users Jakob and Markus were created are missing in this Puppet run:

Notice: Compiled catalog for learning.puppetlabs.vm in environment production in 0.14 seconds
Notice: Finished catalog run in 0.27 seconds

This is due to the idempotent nature of Puppet. As the users Jakob and Markus already exist in the system, Puppet doesn't attempt to recreate these accounts. Idempotency in Puppet means that you can apply the same manifest as many times as you like, and only when the state of the resource in the system is different from the state of the resource declared in the manifest, will Puppet ensure that the required configuration changes are performed according to the manifest.

To demonstrate how Puppet handles idempotency, we will remove the user Markus with the following command, which we are familiar with:

puppet resource user Markus ensure=absent

Then, apply the manifest again with the puppet apply user.pp command, and you can see that the user Jakob, which we did not remove earlier, does not appear in the output but the user Markus is recreated.

Here is the command again:

puppet apply user.pp

The output of the command is as follows:

Notice: Compiled catalog for learning.puppetlabs.vm in environment production in 0.15 seconds
Notice: /Stage[main]/Main/User[Markus]/ensure: created
Notice: Finished catalog run in 0.35 seconds

Puppet command line versus Puppet manifests

So far, we have practiced how to manage system resources from the command line with puppet resource command, and also learned how to manage resources with the Puppet manifest and puppet apply command. When we start expanding our environment with new hosts and increase the number of resources that Puppet manages on these hosts, you will notice that the Puppet command line doesn't scale very well. The Puppet command line typically manages a single resource, such as user Elisa or user Jakob. Each of these resources was created with its own command. If I have 100 user accounts to be managed, then that would result in the same amount of commands to be run, which would be a very tiring job for anyone to do.

Puppet is a configuration management and automation tool that helps you eliminate repetitive tasks, such as creating 100 user accounts. Instead of running the puppet resource command 100 times, it is better if we add all our users once to a single manifest file, call the file with a puppet apply command, and let the Puppet do the hard work for us. Puppet manifests are types of recipes for your system configuration. Once you have described your system configuration in the form of a manifest, you can easily transfer the recipe onto another host and apply the configuration with a single command.

Managing files and directories with a file resource

The phrase "everything is a file" that is often associated with the Linux operating system makes it an ideal environment for Puppet to manage. Puppet is very good at managing files. Puppet's file resource can create files from static source files. You can define the file content with the content attribute, or you can create files with a dynamic content using templates. A file resource can also be used to manage directories and links.

The syntax of a file resource is very similar to the user resource syntax, only the set of available attributes is different. Here is a simple example of how to create an empty directory called /root/Documents:

file {  '/root/Documents':
  ensure => directory;
}

The first line defines the type of resource we want Puppet to manage, followed by the name of the directory that Puppet creates.

The ensure attribute on line two says that the file resource must be a directory. If we omit the ensure attribute, Puppet will create a file instead of a directory.

The closing curly brace } on the third and the last line ends the file resource statement.

Let's do a practical experiment with the file resource and write a manifest file that sets a log in greeting message when the user Jakob logs in. In order to do this, our manifest must fulfill the following two criteria:

  • The user Jakob must have a home directory to store the login greeting message

  • The user Jakob must have a custom .bash_profile file present under the home directory

To start with, let's remove the user Jakob from the system so that we can easily recreate the account with a password, and tell Puppet to create a home directory for the user:

puppet resource user Jakob ensure=absent

Now when the user Jakob has been removed, let's generate a user resource for Jakob and redirect the output to the file called jakobs-login.pp. Again, we use the single > character to create a new file:

puppet resource user Jakob > jakobs-login.pp

Then, using the >> notation to redirect the output to the jakobs-login.pp file, we can generate the file resource snippet for the .bash_profile file that will be placed under the home directory of Jakob with the following command:

puppet resource file /home/Jakob/.bash_profile >> jakobs-login.pp

Now that we have the manifest body ready for editing, we can open the jakobs-login.pp file in the Nano editor:

nano jakobs-login.pp

On opening the file, you should see the following file content:

user { 'Jakob':
  ensure => 'absent',
}
file { '/home/Jakob/.bash_profile':
  ensure => 'absent',
}

Let's begin by changing the ensure attribute value from absent to present for the user resource Jakob.

Then, to tell Puppet to create the home directory for the user, we need to use the managehome attribute and set its value to true. The managehome attribute is specific to a user resource, and we can use it to tell Puppet to create a home directory for the user under the /home directory. The home directory is needed to store the .bash_profile file, which we will take a look at shortly.

Finally, to enable Jakob to log in using the password puppet, we should set the encrypted password attribute value to $1$jrm5tnjw$h8JJ9mCZLmJvIxvDLjw1M/.

This is how the user resource for Jakob should look like after the changes:

user { 'Jakob':
  ensure => 'present',
  managehome => true,
  password => '$1$jrm5tnjw$h8JJ9mCZLmJvIxvDLjw1M/',
}

Before we move on to the file resource, let's save the changes with Ctrl + X and hit Enter. Then, apply the manifest to the puppet apply command:

puppet apply jakobs-login.pp

If the Puppet run was successful, you should see the following output:

Notice: Compiled catalog for learning.puppetlabs.vm in environment production in 0.63 seconds
Notice: /Stage[main]/Main/User[Jakob]/ensure: created
Notice: /Stage[main]/Main/File[/home/Jakob/.bash_profile]/ensure: removed
Notice: Finished catalog run in 0.35 seconds

If we take a look at the third line of the output, we can see that Puppet removed the /home/Jakob/.bash_profile file although we had not yet created it. This is because of the managehome attribute that we declared for the user Jakob, which results in the Linux environment to create the file when the user is created. Because we haven't yet modified the file resource for /home/Jakob/.bash_profile in the manifest, the ensure attribute value is absent. This results in Puppet removing the file.

Don't worry, as we will now tell Puppet to recreate the file with the content that we specify:

  1. Open the jakobs-login.pp manifest file using the Nano editor using the following command:

    nano jakobs-login.pp
    
  2. Using the arrow keys, move to the file resource that currently has the following content:

    file { '/home/Jakob/.bash_profile':
      ensure => 'absent',
    }
    
  3. Instead of updating the ensure attribute value from absent to present, we can remove the attribute altogether and replace it with the content attribute. To greet the user Jakob with his name when he logs in, we can specify the content attribute in the following way:

    file { '/home/Jakob/.bash_profile':
      content => 'echo Hello $(logname)',
    }
    
  4. When you are done with the changes, you can save the file using Ctrl + X and press Enter.

  5. Now let's apply the most recent changes from the manifest;

    puppet apply jakobs-login.pp
    

    The output is as follows:

    Notice: Compiled catalog for learning.puppetlabs.vm in environment production in 0.22 seconds
    Notice:/Stage[main]/Main/File[/home/Jakob/.bash_profile]/ensure: defined content as '{md5}7af0d63debeedf19adbd8bb239f5ab36'
    Notice: Finished catalog run in 0.53 seconds
    
  6. Now, it is the big moment to test whether our configuration changes work as expected. Log out with the exit command and then log in as user Jakob using the password puppet.

    If the configuration changes were successful, you should see the bottom of the login banner, showing the message Hello Jakob.