Print the rspec-puppet catalog, courtesy of @willaerk

Sometimes, when you are writing an rspec-puppet test, you’re not sure exactly how the test should be written. You know that you want to test a resource with some extra attribute, but you may be describing the resource wrong, or using a bad regex to test the contents. Rspec-puppet will helpfully tell you when the code and the test do not match, but it does not always tell you where the mismatch is. In those cases, you want to see the whole catalog to see more detail on the resource attributes.

Let’s look at a very simple profile and its corresponding tests and test output:

[rnelson0@build03 profile:production]$ cat manifests/apache.pp
class profile::apache {
  include ::apache

  firewall { '100 HTTP/S inbound':
    dport  => [80, 443],
    proto  => tcp,
    action => accept,
  }
}
[rnelson0@build03 profile:production]$ cat spec/classes/apache_spec.rb
require 'spec_helper'
describe 'profile::apache', :type => :class do
  let :facts do
  {
    :id                     => 'root',
    :kernel                 => 'Linux',
    :osfamily               => 'RedHat',
    :operatingsystem        => 'RedHat',
    :operatingsystemrelease => '6',
    :concat_basedir         => '/dne',
    :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
  }
  end

  context 'with defaults for all parameters' do
    it { is_expected.to create_class('profile::apache') }
    it { is_expected.to contain_package('httpd') }
    it { is_expected.to contain_user("apache") }
  end
end
[rnelson0@build03 profile:production]$ be rspec spec/classes/apache_spec.rb

profile::apache
  with defaults for all parameters
    should contain Class[profile::apache]
    should contain Package[httpd]
    should contain User[apache]

Finished in 4.74 seconds (files took 2.62 seconds to load)
3 examples, 0 failures
Coverage report generated for RSpec to /home/rnelson0/puppet/controlrepo/dist/profile/coverage. 0.0 / 0.0 LOC (100.0%) covered.

COVERAGE: 100.00% -- 0.0/0.0 lines in 0 files

These tests work, but we can still examine the catalog to see the details of it. To do so, we add a single line to the context block of the test:

    it { pp catalogue.resources }

This will use ruby’s pretty print method to display the contents of the catalog as semi-human-readable output. Here’s what the updated test looks like, as well as a snippet of the 199 lines of output (the apache module includes a LOT of resources by default):

[rnelson0@build03 profile:production±]$ cat spec/classes/apache_spec.rb
require 'spec_helper'
describe 'profile::apache', :type => :class do
  let :facts do
  {
    :id                     => 'root',
    :kernel                 => 'Linux',
    :osfamily               => 'RedHat',
    :operatingsystem        => 'RedHat',
    :operatingsystemrelease => '6',
    :concat_basedir         => '/dne',
    :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
  }
  end

  context 'with defaults for all parameters' do
    it { is_expected.to create_class('profile::apache') }
    it { is_expected.to contain_package('httpd') }
    it { is_expected.to contain_user("apache") }
    it { pp catalogue.resources }
  end
end
[rnelson0@build03 profile:production±]$ be rspec spec/classes/apache_spec.rb
/home/rnelson0/puppet/controlrepo/dist/profile/spec/spec_helper.rb:12:in `block in <top (required)>': [DEPRECATION] ::[] is deprecated. Use ::new instead.

profile::apache
  with defaults for all parameters
    should contain Class[profile::apache]
    should contain Package[httpd]
    should contain User[apache]
[Stage[main]{:name=>"main"},
 Class[Settings]{:name=>"Settings"},
 Class[main]{:name=>"main"},
 Class[Profile::Apache]{:name=>"Profile::Apache"},
 Class[Apache::Version]{:name=>"Apache::Version"},
 Class[Apache::Params]{:name=>"Apache::Params"},
 Class[Apache]{:name=>"Apache", :apache_name=>"httpd", :service_name=>"httpd", :default_mods=>true, :default_vhost=>true, :default_confd_files=>true, :default_ssl_vhost=>false, :default_ssl_cert=>"/etc/pki/tls/certs/localhost.crt", :default_ssl_key=>"/etc/pki/tls/private/localhost.key", :default_type=>"none", :dev_packages=>"httpd-devel", :service_enable=>true, :service_manage=>true, :service_ensure=>"running", :purge_configs=>true, :purge_vdir=>false, :serveradmin=>"root@localhost", :sendfile=>"On", :error_documents=>false, :timeout=>"120", :httpd_dir=>"/etc/httpd", :server_root=>"/etc/httpd", :conf_dir=>"/etc/httpd/conf", :confd_dir=>"/etc/httpd/conf.d", :vhost_dir=>"/etc/httpd/conf.d", :vhost_include_pattern=>"*", :mod_dir=>"/etc/httpd/conf.d", :mpm_module=>"prefork", :lib_path=>"modules", :conf_template=>"apache/httpd.conf.erb", :servername=>"build03.nelson.va", :pidfile=>"run/httpd.pid", :manage_user=>true, :manage_group=>true, :user=>"apache", :group=>"apache", :keepalive=>"Off", :keepalive_timeout=>15, :max_keepalive_requests=>100, :limitreqfieldsize=>"8190", :logroot=>"/var/log/httpd", :log_level=>"warn", :log_formats=>{}, :ports_file=>"/etc/httpd/conf/ports.conf", :docroot=>"/var/www/html", :apache_version=>"2.2", :server_tokens=>"OS", :server_signature=>"On", :trace_enable=>"On", :package_ensure=>"installed", :use_optional_includes=>false, :use_systemd=>true, :mime_types_additional=>{"AddHandler"=>{"type-map"=>"var"}, "AddType"=>{"text/html"=>".shtml"}, "AddOutputFilter"=>{"INCLUDES"=>".shtml"}}, :file_mode=>"0644", :root_directory_options=>["FollowSymLinks"], :root_directory_secured=>false},
 Package[httpd]{:name=>"httpd", :ensure=>"installed", :notify=>Class[Apache::Service]{:name=>"Apache::Service"}},
 User[apache]{:name=>"apache", :ensure=>"present", :gid=>"apache", :require=>Package[httpd]{:name=>"httpd"}},
 Group[apache]{:name=>"apache", :ensure=>"present", :require=>Package[httpd]{:name=>"httpd"}},
 Class[Apache::Service]{:name=>"Apache::Service", :service_name=>"httpd", :service_enable=>true, :service_manage=>true, :service_ensure=>"running"},

When you have a complex test or you’re using a resource type that’s new to you, inspecting the catalog can help you find what you need with a little less trial and error. Thanks to Kristof Willaert (@willaerk) for sharing this!

Edit: Alex Harvey (alexharv074) has previously described a similar method to do this.

4 thoughts on “Print the rspec-puppet catalog, courtesy of @willaerk

  1. Pingback: Dumping the catalog in rspec-puppet | Razor Consulting
  2. Pingback: Debugging rspec-puppet – PUPPETEERS OY
  3. Pingback: Debugging rspec-puppet - PUPPETEERS OY
  4. Pingback: Debugging rspec-puppet - Puppeteers Oy

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s