Book Image

Puppet 4 Essentials, Second Edition - Second Edition

By : Felix Frank, Martin Alfke
Book Image

Puppet 4 Essentials, Second Edition - Second Edition

By: Felix Frank, Martin Alfke

Overview of this book

Puppet is a configuration management tool that allows you to automate all your IT configurations, giving you control over what you do to each Puppet Agent in a network, and when and how you do it. In this age of digital delivery and ubiquitous Internet presence, it's becoming increasingly important to implement scalable and portable solutions, not only in terms of software, but also the systems that run it. The free Ruby-based tool Puppet has established itself as the most successful solution to manage any IT infrastructure. Ranging from local development environments through complex data center setups to scalable cloud implementations, Puppet allows you to handle them all with a unified approach. Puppet 4 Essentials, Second Edition gets you started rapidly and intuitively as you’ll put Puppet’s tools to work right away. It will also highlight the changes associated with performance improvements as well as the new language features in Puppet 4. We’ll start with a quick introduction to Puppet to get you managing your IT systems quickly. You will then learn about the Puppet Agent that comes with an all-in-one (AIO) package and can run on multiple systems. Next, we’ll show you the Puppet Server for high-performance communication and passenger packages. As you progress through the book, the innovative structure and approach of Puppet will be explained with powerful use cases. The difficulties that are inherent to a complex and powerful tool will no longer be a problem for you as you discover Puppet's fascinating intricacies. By the end of the book, you will not only know how to use Puppet, but also its companion tools Facter and Hiera, and will be able to leverage the flexibility and expressive power implemented by their tool chain.
Table of Contents (15 chapters)
Puppet 4 Essentials Second Edition
Credits
About the Authors
About the Reviewer
www.PacktPub.com
Preface
Index

Examining the most notable resource types


To complete our tour of the basic elements of a manifest, let's take a closer look at the resource types that you have already used, and some of the more important ones that you have not yet encountered.

You probably already have a good feeling for the file type, which will ensure the existence of files and directories, along with their permissions. Pulling a file from a repository (usually, a Puppet module) is also a frequent use case, using the source parameter.

For very short files, it is more economic to include the desired content right in the manifest:

file { '/etc/modules':
  ensure  => file,
  content => "# Managed by Puppet!\n\ndrbd\n",
}

Tip

The double quotes allow expansion of escape sequences such as \n.

Another useful capability is managing symbolic links:

file { '/etc/apache2/sites-enabled/001-puppet-lore.org':
  ensure => 'link',
  target => '../sites-available/puppet-lore.org',
}

The next type that you already know is package, and its typical usage is quite intuitive. Make sure that packages are either installed or removed. A notable use case that you have not yet seen is to use the basic package manager instead of apt or yum/zypper. This is useful if the package is not available from a repository:

package { 'haproxy':
  ensure   => present,
  provider => 'dpkg',
  source   => '/opt/packages/haproxy-1.5.1_amd64.dpkg',
}

Your mileage usually increases if you make the effort of setting up a simple repository instead, so that the main package manager can be used after all.

Last but not least, there is a service type, the most important attributes of which you already know. It's worth pointing out that it can serve as a simple shortcut in cases where you don't wish to add a full-fledged init script or something similar. With enough information, the base provider for the service type will manage simple background processes for you:

service { 'count-logins':
  provider  => 'base',
  ensure    => 'running',
  binary    => '/usr/local/bin/cnt-logins',
  start     => '/usr/local/bin/cnt-logins --daemonize',
  subscribe => File['/usr/local/bin/cnt-logins'],
}

Puppet will not only restart the script if it is not running for some reason, but will also restart it whenever the content of the referenced configuration file changes. This only works if Puppet manages the file content and all changes propagate through Puppet only.

Note

If Puppet changes any other property of the script file (for example, the file mode), that too will lead to a restart of the process.

Let's take a look at some other types you will probably need.

The user and group types

Especially in the absence of central registries such as LDAP, it is useful to be able to manage user accounts on each of your machines. There are providers for all supported platforms, however, the available attributes vary. On Linux, the useradd provider is the most common. It allows the management of all fields in /etc/passwd, such as uid and shell, and also group memberships:

group { 'proxy-admins':
  ensure => present,
  gid    => 4002,
}
user { 'john':
  ensure           => present,
  uid              => 2014,
  home             => '/home/john'
  managehome       => true, # <- adds -m to useradd
  gid              => 1000,
  shell            => '/bin/zsh',
  groups           => [ 'proxy-admins' ],
}

As with all resources, Puppet will not only make sure that the user and group exist, but also fix any divergent properties, such as the home directory.

Even though the user depends on the group, (because they cannot be added before the group exists) it need not be expressed in the manifest. The user automatically requires all necessary groups, similar to a file auto requiring its parent directory.

Note

Note that Puppet will also happily manage your LDAP user accounts.

It was mentioned earlier that there are different attributes available, depending on the Operating System. Linux (and the useradd provider) support setting a password, whereas on HP-UX (using the hp-ux provider) the user password cannot be set via Puppet.

In this case, Puppet will only show a warning saying that the user resource type is making use of an unsupported attribute, and will continue managing all other attributes. In other words, using an unsupported attribute in your Puppet DSL code will not break your Puppet run.

The exec resource type

There is one oddball resource type in the Puppet core. Remember our earlier assertion that Puppet is not a specialized scripting engine, but instead, a tool that allows you to model part of your system state in a compelling DSL, and which is capable of altering your system to meet the defined goal. This is why you declare user and group, instead of invoking groupadd and useradd in order. You can do this because Puppet comes with support to manage such entities. This is vastly beneficial because Puppet also knows that on different platforms, other commands are used for account management, and that the arguments can be subtly different on some systems.

Of course, Puppet does not have knowledge of all the conceivable particulars of any supported system. Say that you wish to manage an OpenAFS file server. There are no specific resource types to aid you with this. The ideal solution is to exploit Puppet's plugin system and to write your own types and providers so that your manifests can just reflect the AFS-specific configuration. This is not simple though, and also not worthwhile in cases where you only need Puppet to invoke some exotic commands from very few places in your manifest.

For such cases, Puppet ships with the exec resource type, which allows the execution of custom commands in lieu of an abstract sync action.

For example, it can be used to unpack a tarball in the absence of a proper package:

exec { 'tar cjf /opt/packages/homebrewn-3.2.tar.bz2':
  cwd     => '/opt',
  path    => '/bin:/usr/bin',
  creates => '/opt/homebrewn-3.2',
}

The creates parameter is important for Puppet to tell whether the command needs running—once the specified path exists, the resource counts as synchronized. For commands that do not create a telltale file or directory, there are the alternative parameters, onlyif and unless, to allow Puppet to query the sync state:

exec { 'perl -MCPAN -e "install YAML"': path   => '/bin:/usr/bin', 
  unless => 'cpan -l | grep -qP ^YAML\\b',
}

The query command's exit code determines the state. In the case of unless, the exec command runs if the query fails. This is how the exec type maintains idempotency. Puppet does this automatically for most resource types, but this is not possible for exec, because synchronization is defined so arbitrarily. It becomes your responsibility as the user to define the appropriate queries per resource.

Finally, the exec type resources are the second notable case of receivers for events using notify and subscribe:

exec { 'apt-get update': path        => '/bin:/usr/bin',
  subscribe   => File['/etc/apt/sources.list.d/jenkins.list'],
  refreshonly => true,
}

You can even chain multiple exec resources in this fashion so that each invocation triggers the next one. However, this is a bad practice and degrades Puppet to a (rather flawed) scripting engine. The exec resources should be avoided in favor of regular resources whenever possible. Some resource types that are not part of the core are available as plugins from the Puppet Forge. You will learn more about this topic in Chapter 5, Extending Your Puppet Infrastructure with Modules.

Since exec resources can be used to perform virtually any operation, they are sometimes abused to stand in for more proper resource types. This is a typical antipattern in Puppet manifests. It is safer to regard exec resources as the last resort that is only to be used if all other alternatives have been exhausted.

Tip

All Puppet installations have the type documentation built into the code, which is printable on command line by using the puppet describe command:

puppet describe <type> [-s]

In case you are unsure whether a type exists, you can tell Puppet describe to return a full list of all available resource types:

puppet describe --list

Let's briefly discuss two more types that are supported out of the box. They allow the management of cron jobs, mounted partitions, and shares respectively, which are all frequent requirements in server operation.

The cron resource type

A cron job mainly consists of a command and the recurring time and date at which to run the command. Puppet models the command and each date particle as a property of a resource with the cron type:

cron { 'clean-files':
  ensure      => present,
  user        => 'root',
  command     => '/usr/local/bin/clean-files',
  minute      => '1',
  hour        => '3',
  weekday     => [ '2', '6' ],
  environment => '[email protected]',
}

The environment property allows you to specify one or more variable bindings for cron to add to the job.

The mount resource type

Finally, Puppet will manage all aspects of mountable filesystems for you—including their basic attributes such as the source device and mount point, the mount options, and the current state. A line from the fstab file translates quite literally to a Puppet manifest:

mount { '/media/gluster-data':
  ensure  => 'mounted',
  device  => 'gluster01:/data',
  fstype  => 'glusterfs',
  options => 'defaults,_netdev',
  dump    => 0,
  pass    => 0,
}

For this resource, Puppet will make sure that the filesystem is indeed mounted after the run. Ensuring the unmounted state is also possible, of course; Puppet can also just make sure the entry is present in the fstab file, or absent from the system altogether.