"Show me a completely smooth operation and I'll show you someone who's covering mistakes. Real boats rock." | ||
--Frank Herbert, Chapterhouse: Dune |
In this chapter, we will cover the following recipes:
To avoid these problems, you can use Puppet's noop mode, which means no operation or do nothing. When run with the noop option, Puppet only reports what it would do but doesn't actually do anything. One caveat here is that even during a noop run, pluginsync still runs and any lib
directories in modules will be synced to nodes. This will update external fact definitions and possibly Puppet's types and providers.
You may run noop mode when running puppet agent
or puppet apply
by appending the --noop
switch to the command. You may also create a noop=true
line in your puppet.conf
file within the [agent]
or [main]
sections.
- Create a
noop.pp
manifest that creates a file as follows:file {'/tmp/noop': content => 'nothing', mode => 0644, }
- Now run puppet agent with the
noop
switch:t@mylaptop ~/puppet/manifests $ puppet apply noop.pp --noop Notice: Compiled catalog for mylaptop in environment production in 0.41 seconds Notice: /Stage[main]/Main/File[/tmp/noop]/ensure: current_value absent, should be file (noop) Notice: Class[Main]: Would have triggered 'refresh' from 1 events Notice: Stage[main]: Would have triggered 'refresh' from 1 events Notice: Finished catalog run in 0.02 seconds
- Now run without the
noop
option to see that the file is created:t@mylaptop ~/puppet/manifests $ puppet apply noop.pp Notice: Compiled catalog for mylaptop in environment production in 0.37 seconds Notice: /Stage[main]/Main/File[/tmp/noop]/ensure: defined content as '{md5}3e47b75000b0924b6c9ba5759a7cf15d'
In the noop
mode, Puppet does everything it would normally, with the exception of actually making any changes to the machine (the exec
resources, for example, won't run). It tells you what it would have done, and you can compare this with what you expected to happen. If there are any differences, double-check the manifest or the current state of the machine.
You can also use noop mode as a simple auditing tool. It will tell you whether any changes have been made to the machine since Puppet last applied its manifest. Some organizations require all config changes to be made with Puppet, which is one way of implementing a change control process. Unauthorized changes to the resources managed by Puppet can be detected using Puppet in noop mode and you can then decide whether to merge the changes back into the Puppet manifest or undo them.
- The Auditing resources recipe in Chapter 6, Managing Resources and Files
- The Automatic syntax checking with Git hooks recipe in Chapter 2, Puppet Infrastructure
- The Generating reports recipe in this chapter
- The Testing your Puppet manifests with rspec-puppet recipe in Chapter 9, External Tools and the Puppet Ecosystem
- Create a
noop.pp
manifest that creates a file as follows:file {'/tmp/noop': content => 'nothing', mode => 0644, }
- Now run puppet agent with the
noop
switch:t@mylaptop ~/puppet/manifests $ puppet apply noop.pp --noop Notice: Compiled catalog for mylaptop in environment production in 0.41 seconds Notice: /Stage[main]/Main/File[/tmp/noop]/ensure: current_value absent, should be file (noop) Notice: Class[Main]: Would have triggered 'refresh' from 1 events Notice: Stage[main]: Would have triggered 'refresh' from 1 events Notice: Finished catalog run in 0.02 seconds
- Now run without the
noop
option to see that the file is created:t@mylaptop ~/puppet/manifests $ puppet apply noop.pp Notice: Compiled catalog for mylaptop in environment production in 0.37 seconds Notice: /Stage[main]/Main/File[/tmp/noop]/ensure: defined content as '{md5}3e47b75000b0924b6c9ba5759a7cf15d'
In the noop
mode, Puppet does everything it would normally, with the exception of actually making any changes to the machine (the exec
resources, for example, won't run). It tells you what it would have done, and you can compare this with what you expected to happen. If there are any differences, double-check the manifest or the current state of the machine.
You can also use noop mode as a simple auditing tool. It will tell you whether any changes have been made to the machine since Puppet last applied its manifest. Some organizations require all config changes to be made with Puppet, which is one way of implementing a change control process. Unauthorized changes to the resources managed by Puppet can be detected using Puppet in noop mode and you can then decide whether to merge the changes back into the Puppet manifest or undo them.
- The Auditing resources recipe in Chapter 6, Managing Resources and Files
- The Automatic syntax checking with Git hooks recipe in Chapter 2, Puppet Infrastructure
- The Generating reports recipe in this chapter
- The Testing your Puppet manifests with rspec-puppet recipe in Chapter 9, External Tools and the Puppet Ecosystem
noop
mode, Puppet
You can also use noop mode as a simple auditing tool. It will tell you whether any changes have been made to the machine since Puppet last applied its manifest. Some organizations require all config changes to be made with Puppet, which is one way of implementing a change control process. Unauthorized changes to the resources managed by Puppet can be detected using Puppet in noop mode and you can then decide whether to merge the changes back into the Puppet manifest or undo them.
- The Auditing resources recipe in Chapter 6, Managing Resources and Files
- The Automatic syntax checking with Git hooks recipe in Chapter 2, Puppet Infrastructure
- The Generating reports recipe in this chapter
- The Testing your Puppet manifests with rspec-puppet recipe in Chapter 9, External Tools and the Puppet Ecosystem
- The Auditing resources recipe in Chapter 6, Managing Resources and Files
- The Automatic syntax checking with Git hooks recipe in Chapter 2, Puppet Infrastructure
- The Generating reports recipe in this chapter
- The Testing your Puppet manifests with rspec-puppet recipe in Chapter 9, External Tools and the Puppet Ecosystem
When you use the exec
resources to run commands on the node, Puppet will give you an error message such as the following if a command returns a non-zero exit status:
As you can see, Puppet not only reports that the command failed, but shows its output:
Follow these steps in order to log command output:
- Define an
exec
resource with thelogoutput
parameter as shown in the following code snippet:exec { 'exec with output': command => '/bin/cat /etc/hostname', logoutput => true, }
- Run Puppet:
t@mylaptop ~/puppet/manifests $ puppet apply exec.pp Notice: Compiled catalog for mylaptop in environment production in 0.46 seconds Notice: /Stage[main]/Main/Exec[exec with outout]/returns: mylaptop Notice: /Stage[main]/Main/Exec[exec with outout]/returns: executed successfully Notice: Finished catalog run in 0.06 seconds
- As you can see, even though the command succeeds, Puppet prints the output:
mylaptop
Note
Resource defaults: What's this Exec syntax? It looks like an exec
resource, but it's not. When you use Exec
with a capital E, you're setting the resource default for exec. You may set the resource default for any resource by capitalizing the first letter of the resource type. Anywhere that Puppet see's that resource within the current scope or a nested subscope, it will apply the defaults you define.
If you never want to see the command output, whether it succeeds or fails, use:
More information is available at https://docs.puppetlabs.com/references/latest/type.html#exec.
exec
resource with the logoutput
parameter as shown in the following code snippet:exec { 'exec with output': command => '/bin/cat /etc/hostname', logoutput => true, }
t@mylaptop ~/puppet/manifests $ puppet apply exec.pp Notice: Compiled catalog for mylaptop in environment production in 0.46 seconds Notice: /Stage[main]/Main/Exec[exec with outout]/returns: mylaptop Notice: /Stage[main]/Main/Exec[exec with outout]/returns: executed successfully Notice: Finished catalog run in 0.06 seconds
mylaptop
Note
Resource defaults: What's this Exec syntax? It looks like an exec
resource, but it's not. When you use Exec
with a capital E, you're setting the resource default for exec. You may set the resource default for any resource by capitalizing the first letter of the resource type. Anywhere that Puppet see's that resource within the current scope or a nested subscope, it will apply the defaults you define.
If you never want to see the command output, whether it succeeds or fails, use:
More information is available at https://docs.puppetlabs.com/references/latest/type.html#exec.
logoutput
attribute has three possible settings:
false
: This never
Note
Resource defaults: What's this Exec syntax? It looks like an exec
resource, but it's not. When you use Exec
with a capital E, you're setting the resource default for exec. You may set the resource default for any resource by capitalizing the first letter of the resource type. Anywhere that Puppet see's that resource within the current scope or a nested subscope, it will apply the defaults you define.
If you never want to see the command output, whether it succeeds or fails, use:
More information is available at https://docs.puppetlabs.com/references/latest/type.html#exec.
logoutput
to always display command output for all exec
resources by defining the following in your site.pp
file:
Note
Resource defaults: What's this Exec syntax? It looks like an exec
resource, but it's not. When you use Exec
with a capital E, you're setting the resource default for exec. You may set the resource default for any resource by capitalizing the first letter of the resource type. Anywhere that Puppet see's that resource within the current scope or a nested subscope, it will apply the defaults you define.
If you never want to see the command output, whether it succeeds or fails, use:
More information is available at https://docs.puppetlabs.com/references/latest/type.html#exec.
It can be very helpful when debugging problems if you can print out information at a certain point in the manifest. This is a good way to tell, for example, if a variable isn't defined or has an unexpected value. Sometimes it's useful just to know that a particular piece of code has been run. Puppet's notify
resource lets you print out such messages.
You can refer to variables in the message:
Puppet will interpolate the values in the printout:
The double colon (::
) before the fact name tells Puppet that this is a variable in top scope (accessible to all classes) and not local to the class. For more about how Puppet handles variable scope, see the Puppet Labs article:
Puppet compiles your manifests into a catalog; the order in which resources are executed on the client (node) may not be the same as the order of the resources within your source files. When you are using a notify
resource for debugging, you should use resource chaining to ensure that the notify resource
is executed before or after your failing resource.
If you don't chain the resource or use a metaparameter such as before
or require
, there is no guarantee your notify
statement will be executed near the other resources you are interested in debugging. More information on resource ordering can be found at https://docs.puppetlabs.com/puppet/latest/reference/lang_relationships.html.
For example, to have your notify resource
run after 'failing exec'
in the preceding code snippet, use:
notify { 'Resource X has been applied': require => Exec['failing exec'], }
Note, however, that in this case the notify resource
will fail to execute since the exec failed. When a resource fails, all the resources that depended on that resource are skipped:
notify {'failed exec failed': require => Exec['failing exec'] }
When we run Puppet, we see that the notify resource
is skipped:
t@mylaptop ~/puppet/manifests $ puppet apply fail.pp ... Error: /bin/grepmylaptop /etc/hosts returned 1 instead of one of [0] Error: /Stage[main]/Main/Exec[failing exec]/returns: change from notrun to 0 failed: /bin/grepmylaptop /etc/hosts returned 1 instead of one of [0] Notice: /Stage[main]/Main/Notify[failed exec failed]: Dependency Exec[failing exec] has failures: true Warning: /Stage[main]/Main/Notify[failed exec failed]: Skipping because of failed dependencies Notice: Finished catalog run in 0.06 seconds
notify
resource in your manifest at the point you want to investigate:
You can refer to variables in the message:
Puppet will interpolate the values in the printout:
The double colon (::
) before the fact name tells Puppet that this is a variable in top scope (accessible to all classes) and not local to the class. For more about how Puppet handles variable scope, see the Puppet Labs article:
Puppet compiles your manifests into a catalog; the order in which resources are executed on the client (node) may not be the same as the order of the resources within your source files. When you are using a notify
resource for debugging, you should use resource chaining to ensure that the notify resource
is executed before or after your failing resource.
If you don't chain the resource or use a metaparameter such as before
or require
, there is no guarantee your notify
statement will be executed near the other resources you are interested in debugging. More information on resource ordering can be found at https://docs.puppetlabs.com/puppet/latest/reference/lang_relationships.html.
For example, to have your notify resource
run after 'failing exec'
in the preceding code snippet, use:
notify { 'Resource X has been applied': require => Exec['failing exec'], }
Note, however, that in this case the notify resource
will fail to execute since the exec failed. When a resource fails, all the resources that depended on that resource are skipped:
notify {'failed exec failed': require => Exec['failing exec'] }
When we run Puppet, we see that the notify resource
is skipped:
t@mylaptop ~/puppet/manifests $ puppet apply fail.pp ... Error: /bin/grepmylaptop /etc/hosts returned 1 instead of one of [0] Error: /Stage[main]/Main/Exec[failing exec]/returns: change from notrun to 0 failed: /bin/grepmylaptop /etc/hosts returned 1 instead of one of [0] Notice: /Stage[main]/Main/Notify[failed exec failed]: Dependency Exec[failing exec] has failures: true Warning: /Stage[main]/Main/Notify[failed exec failed]: Skipping because of failed dependencies Notice: Finished catalog run in 0.06 seconds
You can refer to variables in the message:
Puppet will interpolate the values in the printout:
The double colon (::
) before the fact name tells Puppet that this is a variable in top scope (accessible to all classes) and not local to the class. For more about how Puppet handles variable scope, see the Puppet Labs article:
Puppet compiles your manifests into a catalog; the order in which resources are executed on the client (node) may not be the same as the order of the resources within your source files. When you are using a notify
resource for debugging, you should use resource chaining to ensure that the notify resource
is executed before or after your failing resource.
If you don't chain the resource or use a metaparameter such as before
or require
, there is no guarantee your notify
statement will be executed near the other resources you are interested in debugging. More information on resource ordering can be found at https://docs.puppetlabs.com/puppet/latest/reference/lang_relationships.html.
For example, to have your notify resource
run after 'failing exec'
in the preceding code snippet, use:
notify { 'Resource X has been applied': require => Exec['failing exec'], }
Note, however, that in this case the notify resource
will fail to execute since the exec failed. When a resource fails, all the resources that depended on that resource are skipped:
notify {'failed exec failed': require => Exec['failing exec'] }
When we run Puppet, we see that the notify resource
is skipped:
t@mylaptop ~/puppet/manifests $ puppet apply fail.pp ... Error: /bin/grepmylaptop /etc/hosts returned 1 instead of one of [0] Error: /Stage[main]/Main/Exec[failing exec]/returns: change from notrun to 0 failed: /bin/grepmylaptop /etc/hosts returned 1 instead of one of [0] Notice: /Stage[main]/Main/Notify[failed exec failed]: Dependency Exec[failing exec] has failures: true Warning: /Stage[main]/Main/Notify[failed exec failed]: Skipping because of failed dependencies Notice: Finished catalog run in 0.06 seconds
notify
statements. Additionally, we can treat the notify
calls the same as other resources, having them require or be required by other resources.
You can refer to variables in the message:
Puppet will interpolate the values in the printout:
The double colon (::
) before the fact name tells Puppet that this is a variable in top scope (accessible to all classes) and not local to the class. For more about how Puppet handles variable scope, see the Puppet Labs article:
Puppet compiles your manifests into a catalog; the order in which resources are executed on the client (node) may not be the same as the order of the resources within your source files. When you are using a notify
resource for debugging, you should use resource chaining to ensure that the notify resource
is executed before or after your failing resource.
If you don't chain the resource or use a metaparameter such as before
or require
, there is no guarantee your notify
statement will be executed near the other resources you are interested in debugging. More information on resource ordering can be found at https://docs.puppetlabs.com/puppet/latest/reference/lang_relationships.html.
For example, to have your notify resource
run after 'failing exec'
in the preceding code snippet, use:
notify { 'Resource X has been applied': require => Exec['failing exec'], }
Note, however, that in this case the notify resource
will fail to execute since the exec failed. When a resource fails, all the resources that depended on that resource are skipped:
notify {'failed exec failed': require => Exec['failing exec'] }
When we run Puppet, we see that the notify resource
is skipped:
t@mylaptop ~/puppet/manifests $ puppet apply fail.pp ... Error: /bin/grepmylaptop /etc/hosts returned 1 instead of one of [0] Error: /Stage[main]/Main/Exec[failing exec]/returns: change from notrun to 0 failed: /bin/grepmylaptop /etc/hosts returned 1 instead of one of [0] Notice: /Stage[main]/Main/Notify[failed exec failed]: Dependency Exec[failing exec] has failures: true Warning: /Stage[main]/Main/Notify[failed exec failed]: Skipping because of failed dependencies Notice: Finished catalog run in 0.06 seconds
Puppet will interpolate the values in the printout:
The double colon (::
) before the fact name tells Puppet that this is a variable in top scope (accessible to all classes) and not local to the class. For more about how Puppet handles variable scope, see the Puppet Labs article:
Puppet compiles your manifests into a catalog; the order in which resources are executed on the client (node) may not be the same as the order of the resources within your source files. When you are using a notify
resource for debugging, you should use resource chaining to ensure that the notify resource
is executed before or after your failing resource.
If you don't chain the resource or use a metaparameter such as before
or require
, there is no guarantee your notify
statement will be executed near the other resources you are interested in debugging. More information on resource ordering can be found at https://docs.puppetlabs.com/puppet/latest/reference/lang_relationships.html.
For example, to have your notify resource
run after 'failing exec'
in the preceding code snippet, use:
notify { 'Resource X has been applied': require => Exec['failing exec'], }
Note, however, that in this case the notify resource
will fail to execute since the exec failed. When a resource fails, all the resources that depended on that resource are skipped:
notify {'failed exec failed': require => Exec['failing exec'] }
When we run Puppet, we see that the notify resource
is skipped:
t@mylaptop ~/puppet/manifests $ puppet apply fail.pp ... Error: /bin/grepmylaptop /etc/hosts returned 1 instead of one of [0] Error: /Stage[main]/Main/Exec[failing exec]/returns: change from notrun to 0 failed: /bin/grepmylaptop /etc/hosts returned 1 instead of one of [0] Notice: /Stage[main]/Main/Notify[failed exec failed]: Dependency Exec[failing exec] has failures: true Warning: /Stage[main]/Main/Notify[failed exec failed]: Skipping because of failed dependencies Notice: Finished catalog run in 0.06 seconds
If you don't chain the resource or use a metaparameter such as before
or require
, there is no guarantee your notify
statement will be executed near the other resources you are interested in debugging. More information on resource ordering can be found at https://docs.puppetlabs.com/puppet/latest/reference/lang_relationships.html.
For example, to have your notify resource
run after 'failing exec'
in the preceding code snippet, use:
notify { 'Resource X has been applied': require => Exec['failing exec'], }
Note, however, that in this case the notify resource
will fail to execute since the exec failed. When a resource fails, all the resources that depended on that resource are skipped:
notify {'failed exec failed': require => Exec['failing exec'] }
When we run Puppet, we see that the notify resource
is skipped:
t@mylaptop ~/puppet/manifests $ puppet apply fail.pp ... Error: /bin/grepmylaptop /etc/hosts returned 1 instead of one of [0] Error: /Stage[main]/Main/Exec[failing exec]/returns: change from notrun to 0 failed: /bin/grepmylaptop /etc/hosts returned 1 instead of one of [0] Notice: /Stage[main]/Main/Notify[failed exec failed]: Dependency Exec[failing exec] has failures: true Warning: /Stage[main]/Main/Notify[failed exec failed]: Skipping because of failed dependencies Notice: Finished catalog run in 0.06 seconds
If you're managing a lot of machines, Puppet's reporting facility can give you some valuable information on what's actually happening out there.
With reporting enabled, Puppet will generate a report file, containing data such as:
By default, these reports are stored on the node at /var/lib/puppet/reports
in a directory named after the hostname, but you can specify a different destination using the reportdir
option. You can create your own scripts to process these reports (which are in the standard YAML format). When we run puppet agent on cookbook.example.com
, the following file is created on the master:
You won't see any additional output, but a report file will be generated in the report
directory.
You can also see some overall statistics about a Puppet run by supplying the --summarize
switch:
Puppet can generate different types of reports with the reports option in the [main]
or [master]
section of puppet.conf
on your Puppet master servers. There are several built-in report types listed at https://docs.puppetlabs.com/references/latest/report.html. In addition to the built-in report types, there are some community developed reports that are quite useful. The Foreman (http://theforeman.org), for example, provides a Foreman report type that you can enable to forward your node reports to the Foreman.
- The Auditing resources recipe in Chapter 6, Managing Resources and Files
puppet.conf
: within the [main]
or [agent]
sections:
With reporting enabled, Puppet will generate a report file, containing data such as:
By default, these reports are stored on the node at /var/lib/puppet/reports
in a directory named after the hostname, but you can specify a different destination using the reportdir
option. You can create your own scripts to process these reports (which are in the standard YAML format). When we run puppet agent on cookbook.example.com
, the following file is created on the master:
You won't see any additional output, but a report file will be generated in the report
directory.
You can also see some overall statistics about a Puppet run by supplying the --summarize
switch:
Puppet can generate different types of reports with the reports option in the [main]
or [master]
section of puppet.conf
on your Puppet master servers. There are several built-in report types listed at https://docs.puppetlabs.com/references/latest/report.html. In addition to the built-in report types, there are some community developed reports that are quite useful. The Foreman (http://theforeman.org), for example, provides a Foreman report type that you can enable to forward your node reports to the Foreman.
- The Auditing resources recipe in Chapter 6, Managing Resources and Files
You won't see any additional output, but a report file will be generated in the report
directory.
You can also see some overall statistics about a Puppet run by supplying the --summarize
switch:
Puppet can generate different types of reports with the reports option in the [main]
or [master]
section of puppet.conf
on your Puppet master servers. There are several built-in report types listed at https://docs.puppetlabs.com/references/latest/report.html. In addition to the built-in report types, there are some community developed reports that are quite useful. The Foreman (http://theforeman.org), for example, provides a Foreman report type that you can enable to forward your node reports to the Foreman.
- The Auditing resources recipe in Chapter 6, Managing Resources and Files
report_server
in the [agent]
section of puppet.conf
.
--report
switch to the command line when you run Puppet agent manually:
report
directory.
--summarize
switch:
Puppet can generate different types of reports with the reports option in the [main]
or [master]
section of puppet.conf
on your Puppet master servers. There are several built-in report types listed at https://docs.puppetlabs.com/references/latest/report.html. In addition to the built-in report types, there are some community developed reports that are quite useful. The Foreman (http://theforeman.org), for example, provides a Foreman report type that you can enable to forward your node reports to the Foreman.
- The Auditing resources recipe in Chapter 6, Managing Resources and Files
[main]
or [master]
section of puppet.conf
on your Puppet master servers. There are several built-in report types
listed at https://docs.puppetlabs.com/references/latest/report.html. In addition to the built-in report types, there are some community developed reports that are quite useful. The Foreman (http://theforeman.org), for example, provides a Foreman report type that you can enable to forward your node reports to the Foreman.
- The Auditing resources recipe in Chapter 6, Managing Resources and Files
- Chapter 6, Managing Resources and Files
Follow these steps to generate HTML documentation for your manifest:
- Run the following command:
t@mylaptop ~/puppet $ puppet doc --all --outputdir=/tmp/puppet --mode rdoc --modulepath=modules/
- This will generate a set of HTML files at
/tmp/puppet
. Open the top-levelindex.html
file with your web browser (file:///tmp/puppet/index.html
), and you'll see something like the following screenshot: - Click the classes link on the left and select the Apache module, something similar to the following will be displayed:
The puppet doc
command creates a structured HTML documentation tree similar to that produced by RDoc, the popular Ruby documentation generator. This makes it easier to understand how different parts of the manifest relate to one another.
The puppet doc
command will generate basic documentation of your manifests as they stand, but you can include more useful information by adding comments to your manifest files, using the standard RDoc syntax. When we created our base class using puppet module generate, these comments were created for us:
After generating the HTML documentation, we can see the result for the base module as shown in the following screenshot:
HTML documentation for your manifest:
- Run the following command:
t@mylaptop ~/puppet $ puppet doc --all --outputdir=/tmp/puppet --mode rdoc --modulepath=modules/
- This will generate a set of HTML files at
/tmp/puppet
. Open the top-levelindex.html
file with your web browser (file:///tmp/puppet/index.html
), and you'll see something like the following screenshot: - Click the classes link on the left and select the Apache module, something similar to the following will be displayed:
The puppet doc
command creates a structured HTML documentation tree similar to that produced by RDoc, the popular Ruby documentation generator. This makes it easier to understand how different parts of the manifest relate to one another.
The puppet doc
command will generate basic documentation of your manifests as they stand, but you can include more useful information by adding comments to your manifest files, using the standard RDoc syntax. When we created our base class using puppet module generate, these comments were created for us:
After generating the HTML documentation, we can see the result for the base module as shown in the following screenshot:
puppet doc
command
creates a structured HTML documentation tree similar to that produced by RDoc, the popular Ruby documentation generator. This makes it easier to understand how different parts of the manifest relate to one another.
The puppet doc
command will generate basic documentation of your manifests as they stand, but you can include more useful information by adding comments to your manifest files, using the standard RDoc syntax. When we created our base class using puppet module generate, these comments were created for us:
After generating the HTML documentation, we can see the result for the base module as shown in the following screenshot:
puppet doc
command will
generate basic documentation of your manifests as they stand, but you can include more useful information by adding comments to your manifest files, using the standard RDoc syntax. When we created our base class using puppet module generate, these comments were created for us:
After generating the HTML documentation, we can see the result for the base module as shown in the following screenshot:
Dependencies can get complicated quickly, and it's easy to end up with a circular dependency (where A depends on B, which depends on A) that will cause Puppet to complain and stop working. Fortunately, Puppet's --graph
option makes it easy to generate a diagram of your resources and the dependencies between them, which can be a big help in fixing such problems.
Follow these steps to generate a dependency graph for your manifest:
- Create the directories for a new
trifecta
module:ubuntu@cookbook:~/puppet$ mkdir modules/trifecta ubuntu@cookbook:~/puppet$ mkdir modules/trifecta/manifests ubuntu@cookbook:~/puppet$ mkdir modules/trifecta/files
- Create the file
modules/trifecta/manifests/init.pp
with the following code containing a deliberate circular dependency (can you spot it?):class trifecta { package { 'ntp': ensure => installed, require => File['/etc/ntp.conf'], } service { 'ntp': ensure => running, require => Package['ntp'], } file { '/etc/ntp.conf': source => 'puppet:///modules/trifecta/ntp.conf', notify => Service['ntp'], require => Package['ntp'], } }
- Create a simple
ntp.conf
file:t@mylaptop~/puppet $ cd modules/trifecta/files t@mylaptop~/puppet/modules/trifecta/files $ echo "server 127.0.0.1" >ntp.conf
- Since we'll be working locally on this problem, create a
trifecta.pp
manifest that includes the broken trifecta class:include trifecta
- Run Puppet:
t@mylaptop ~/puppet/manifests $ puppet apply trifecta.pp Notice: Compiled catalog for mylaptop in environment production in 1.32 seconds Error: Could not apply complete catalog: Found 1 dependency cycle: (File[/etc/ntp.conf] => Package[ntp] => File[/etc/ntp.conf]) Try the '--graph' option and opening the resulting '.dot' file in OmniGraffle or GraphViz
- Run Puppet with the
--graph
option as suggested:t@mylaptop ~/puppet/manifests $ puppet apply trifecta.pp --graph Notice: Compiled catalog for mylaptop in environment production in 1.26 seconds Error: Could not apply complete catalog: Found 1 dependency cycle: (File[/etc/ntp.conf] => Package[ntp] => File[/etc/ntp.conf]) Cycle graph written to /home/tuphill/.puppet/var/state/graphs/cycles.dot. Notice: Finished catalog run in 0.03 seconds
- Check whether the graph files have been created:
t@mylaptop ~/puppet/manifests $ cd ~/.puppet/var/state/graphs t@mylaptop ~/.puppet/var/state/graphs $ ls -l total 16 -rw-rw-r--. 1 thomasthomas 121 Nov 23 23:11 cycles.dot -rw-rw-r--. 1 thomasthomas 2885 Nov 23 23:11 expanded_relationships.dot -rw-rw-r--. 1 thomasthomas 1557 Nov 23 23:11 relationships.dot -rw-rw-r--. 1 thomasthomas 1680 Nov 23 23:11 resources.dot
- Create a graphic using the
dot
command as follows:ubuntu@cookbook:~/puppet$ dot -Tpng -o relationships.png /var/lib/puppet/state/graphs/relationships.dot
- The graphic will look something like the this:
When you run puppet agent --graph
(or enable the graph
option in puppet.conf
), Puppet will generate three graphs in the DOT format (a graphics language):
resources.dot
: This shows the hierarchical structure of your classes and resources, but without dependenciesrelationships.dot
: This shows the dependencies between resources as arrows, as shown in the preceding imageexpanded_relationships.dot
: This is a more detailed version of the relationships graph
To fix the circular dependency problem, all you need to do is remove one of the dependency lines and break the circle. The following code fixes the problem:
In this graph it is easy to see that Package[ntp] is the first resource to be applied, then File[/etc/ntp.conf], and finally Service[ntp].
Tip
A graph such as that shown previously is known as a Directed Acyclic Graph (DAG). Reducing the resources to a DAG ensures that Puppet can calculate the shortest path of all the vertices (resources) in linear time. For more information on DAGs, look at http://en.wikipedia.org/wiki/Directed_acyclic_graph.
Resource and relationship graphs can be useful even when you don't have a bug to find. If you have a very complex network of classes and resources, for example, studying the resources graph can help you see where to simplify things. Similarly, when dependencies become too complicated to understand from reading the manifest, the graphs can be a useful form of documentation. For instance, a graph will make it readily apparent which resources have the most dependencies and which resources are required by the most other resources. Resources that are required by a large number of other resources will have numerous arrows pointing at them.
- The Using run stages recipe in Chapter 3, Writing Better Manifests
graphviz
package to view the diagram files:
Follow these steps to generate a dependency graph for your manifest:
- Create the directories for a new
trifecta
module:ubuntu@cookbook:~/puppet$ mkdir modules/trifecta ubuntu@cookbook:~/puppet$ mkdir modules/trifecta/manifests ubuntu@cookbook:~/puppet$ mkdir modules/trifecta/files
- Create the file
modules/trifecta/manifests/init.pp
with the following code containing a deliberate circular dependency (can you spot it?):class trifecta { package { 'ntp': ensure => installed, require => File['/etc/ntp.conf'], } service { 'ntp': ensure => running, require => Package['ntp'], } file { '/etc/ntp.conf': source => 'puppet:///modules/trifecta/ntp.conf', notify => Service['ntp'], require => Package['ntp'], } }
- Create a simple
ntp.conf
file:t@mylaptop~/puppet $ cd modules/trifecta/files t@mylaptop~/puppet/modules/trifecta/files $ echo "server 127.0.0.1" >ntp.conf
- Since we'll be working locally on this problem, create a
trifecta.pp
manifest that includes the broken trifecta class:include trifecta
- Run Puppet:
t@mylaptop ~/puppet/manifests $ puppet apply trifecta.pp Notice: Compiled catalog for mylaptop in environment production in 1.32 seconds Error: Could not apply complete catalog: Found 1 dependency cycle: (File[/etc/ntp.conf] => Package[ntp] => File[/etc/ntp.conf]) Try the '--graph' option and opening the resulting '.dot' file in OmniGraffle or GraphViz
- Run Puppet with the
--graph
option as suggested:t@mylaptop ~/puppet/manifests $ puppet apply trifecta.pp --graph Notice: Compiled catalog for mylaptop in environment production in 1.26 seconds Error: Could not apply complete catalog: Found 1 dependency cycle: (File[/etc/ntp.conf] => Package[ntp] => File[/etc/ntp.conf]) Cycle graph written to /home/tuphill/.puppet/var/state/graphs/cycles.dot. Notice: Finished catalog run in 0.03 seconds
- Check whether the graph files have been created:
t@mylaptop ~/puppet/manifests $ cd ~/.puppet/var/state/graphs t@mylaptop ~/.puppet/var/state/graphs $ ls -l total 16 -rw-rw-r--. 1 thomasthomas 121 Nov 23 23:11 cycles.dot -rw-rw-r--. 1 thomasthomas 2885 Nov 23 23:11 expanded_relationships.dot -rw-rw-r--. 1 thomasthomas 1557 Nov 23 23:11 relationships.dot -rw-rw-r--. 1 thomasthomas 1680 Nov 23 23:11 resources.dot
- Create a graphic using the
dot
command as follows:ubuntu@cookbook:~/puppet$ dot -Tpng -o relationships.png /var/lib/puppet/state/graphs/relationships.dot
- The graphic will look something like the this:
When you run puppet agent --graph
(or enable the graph
option in puppet.conf
), Puppet will generate three graphs in the DOT format (a graphics language):
resources.dot
: This shows the hierarchical structure of your classes and resources, but without dependenciesrelationships.dot
: This shows the dependencies between resources as arrows, as shown in the preceding imageexpanded_relationships.dot
: This is a more detailed version of the relationships graph
To fix the circular dependency problem, all you need to do is remove one of the dependency lines and break the circle. The following code fixes the problem:
In this graph it is easy to see that Package[ntp] is the first resource to be applied, then File[/etc/ntp.conf], and finally Service[ntp].
Tip
A graph such as that shown previously is known as a Directed Acyclic Graph (DAG). Reducing the resources to a DAG ensures that Puppet can calculate the shortest path of all the vertices (resources) in linear time. For more information on DAGs, look at http://en.wikipedia.org/wiki/Directed_acyclic_graph.
Resource and relationship graphs can be useful even when you don't have a bug to find. If you have a very complex network of classes and resources, for example, studying the resources graph can help you see where to simplify things. Similarly, when dependencies become too complicated to understand from reading the manifest, the graphs can be a useful form of documentation. For instance, a graph will make it readily apparent which resources have the most dependencies and which resources are required by the most other resources. Resources that are required by a large number of other resources will have numerous arrows pointing at them.
- The Using run stages recipe in Chapter 3, Writing Better Manifests
generate a dependency graph for your manifest:
- Create the directories for a new
trifecta
module:ubuntu@cookbook:~/puppet$ mkdir modules/trifecta ubuntu@cookbook:~/puppet$ mkdir modules/trifecta/manifests ubuntu@cookbook:~/puppet$ mkdir modules/trifecta/files
- Create the file
modules/trifecta/manifests/init.pp
with the following code containing a deliberate circular dependency (can you spot it?):class trifecta { package { 'ntp': ensure => installed, require => File['/etc/ntp.conf'], } service { 'ntp': ensure => running, require => Package['ntp'], } file { '/etc/ntp.conf': source => 'puppet:///modules/trifecta/ntp.conf', notify => Service['ntp'], require => Package['ntp'], } }
- Create a simple
ntp.conf
file:t@mylaptop~/puppet $ cd modules/trifecta/files t@mylaptop~/puppet/modules/trifecta/files $ echo "server 127.0.0.1" >ntp.conf
- Since we'll be working locally on this problem, create a
trifecta.pp
manifest that includes the broken trifecta class:include trifecta
- Run Puppet:
t@mylaptop ~/puppet/manifests $ puppet apply trifecta.pp Notice: Compiled catalog for mylaptop in environment production in 1.32 seconds Error: Could not apply complete catalog: Found 1 dependency cycle: (File[/etc/ntp.conf] => Package[ntp] => File[/etc/ntp.conf]) Try the '--graph' option and opening the resulting '.dot' file in OmniGraffle or GraphViz
- Run Puppet with the
--graph
option as suggested:t@mylaptop ~/puppet/manifests $ puppet apply trifecta.pp --graph Notice: Compiled catalog for mylaptop in environment production in 1.26 seconds Error: Could not apply complete catalog: Found 1 dependency cycle: (File[/etc/ntp.conf] => Package[ntp] => File[/etc/ntp.conf]) Cycle graph written to /home/tuphill/.puppet/var/state/graphs/cycles.dot. Notice: Finished catalog run in 0.03 seconds
- Check whether the graph files have been created:
t@mylaptop ~/puppet/manifests $ cd ~/.puppet/var/state/graphs t@mylaptop ~/.puppet/var/state/graphs $ ls -l total 16 -rw-rw-r--. 1 thomasthomas 121 Nov 23 23:11 cycles.dot -rw-rw-r--. 1 thomasthomas 2885 Nov 23 23:11 expanded_relationships.dot -rw-rw-r--. 1 thomasthomas 1557 Nov 23 23:11 relationships.dot -rw-rw-r--. 1 thomasthomas 1680 Nov 23 23:11 resources.dot
- Create a graphic using the
dot
command as follows:ubuntu@cookbook:~/puppet$ dot -Tpng -o relationships.png /var/lib/puppet/state/graphs/relationships.dot
- The graphic will look something like the this:
When you run puppet agent --graph
(or enable the graph
option in puppet.conf
), Puppet will generate three graphs in the DOT format (a graphics language):
resources.dot
: This shows the hierarchical structure of your classes and resources, but without dependenciesrelationships.dot
: This shows the dependencies between resources as arrows, as shown in the preceding imageexpanded_relationships.dot
: This is a more detailed version of the relationships graph
To fix the circular dependency problem, all you need to do is remove one of the dependency lines and break the circle. The following code fixes the problem:
In this graph it is easy to see that Package[ntp] is the first resource to be applied, then File[/etc/ntp.conf], and finally Service[ntp].
Tip
A graph such as that shown previously is known as a Directed Acyclic Graph (DAG). Reducing the resources to a DAG ensures that Puppet can calculate the shortest path of all the vertices (resources) in linear time. For more information on DAGs, look at http://en.wikipedia.org/wiki/Directed_acyclic_graph.
Resource and relationship graphs can be useful even when you don't have a bug to find. If you have a very complex network of classes and resources, for example, studying the resources graph can help you see where to simplify things. Similarly, when dependencies become too complicated to understand from reading the manifest, the graphs can be a useful form of documentation. For instance, a graph will make it readily apparent which resources have the most dependencies and which resources are required by the most other resources. Resources that are required by a large number of other resources will have numerous arrows pointing at them.
- The Using run stages recipe in Chapter 3, Writing Better Manifests
resources.dot
: This shows the hierarchical structure of your classes and resources, but without dependenciesrelationships.dot
: This shows the dependencies between resources as arrows, as shown in the preceding imageexpanded_relationships.dot
: This is a more detailed version of the relationships graph
To fix the circular dependency problem, all you need to do is remove one of the dependency lines and break the circle. The following code fixes the problem:
In this graph it is easy to see that Package[ntp] is the first resource to be applied, then File[/etc/ntp.conf], and finally Service[ntp].
Tip
A graph such as that shown previously is known as a Directed Acyclic Graph (DAG). Reducing the resources to a DAG ensures that Puppet can calculate the shortest path of all the vertices (resources) in linear time. For more information on DAGs, look at http://en.wikipedia.org/wiki/Directed_acyclic_graph.
Resource and relationship graphs can be useful even when you don't have a bug to find. If you have a very complex network of classes and resources, for example, studying the resources graph can help you see where to simplify things. Similarly, when dependencies become too complicated to understand from reading the manifest, the graphs can be a useful form of documentation. For instance, a graph will make it readily apparent which resources have the most dependencies and which resources are required by the most other resources. Resources that are required by a large number of other resources will have numerous arrows pointing at them.
- The Using run stages recipe in Chapter 3, Writing Better Manifests
and relationship graphs can be useful even when you don't have a bug to find. If you have a very complex network of classes and resources, for example, studying the resources graph can help you see where to simplify things. Similarly, when dependencies become too complicated to understand from reading the manifest, the graphs can be a useful form of documentation. For instance, a graph will make it readily apparent which resources have the most dependencies and which resources are required by the most other resources. Resources that are required by a large number of other resources will have numerous arrows pointing at them.
- The Using run stages recipe in Chapter 3, Writing Better Manifests
- Chapter 3, Writing Better Manifests
Here are some of the most common errors you might encounter, and what to do about them.
The source file may not be present or may not be in the right location in the Puppet repo:
This one has caused me a bit of puzzlement in the past. Puppet's complaining about a duplicate definition, and normally if you have two resources with the same name, Puppet will helpfully tell you where they are both defined. But in this case, it's indicating the same file and line number for both. How can one resource be a duplicate of itself?
When we run Puppet, the same error is printed twice:
The double quotes are required when you want Puppet to interpolate the value of a variable into a string.
XXX
is a file resource, you may have accidentally typed puppet://modules...
in a file source instead of puppet:///modules...
(note the triple slash):
--debug
switch, to get more useful information:
puppet -verbose
instead of puppet --verbose
. This kind of error can be hard to see:
You probably know that Puppet's configuration settings are stored in puppet.conf
, but there are many parameters, and those that aren't listed in puppet.conf
will take a default value. How can you see the value of any configuration parameter, regardless of whether or not it's explicitly set in puppet.conf
? The answer is to use the puppet config print
command.
less
if you'd like to browse the available configuration settings):
puppet config print
will