Horse O'Houlihan
Horse O'Houlihan

Reputation: 1779

puppet - How to debug and test to see if your module is working properly

I wrote a simple module to install a package (BioPerl) on a Ubuntu VM. The whole init.pp file is here: https://gist.github.com/anonymous/17b4c31bf7309aff14dfdcd378e44f40

The problem is it doesn't work, and it gives me no feedback to let me know why it doesn't work. There are 3 simple steps in the module. I checked and it didn't do any of them. Heres the first 2:

Step 1: Download an archive and save it to /usr/local/lib

  exec { 'bioperl-download':
    command => "sudo /usr/bin/wget --no-check-certificate -O ${archive_path} ${package_uri}",
    require => Package['wget']
  }

Step 2: Extract the archive

  exec { 'bioperl-extract':
    command => "sudo /usr/bin/tar zxvf ${archive_path} --directory ${install_path}; sudo rm ${archive_path}",
    require => Exec['bioperl-download']
  }

pretty simple. But I have no idea where the problem is because I can't see what its doing. The provisioner is set to verbose mode, and here are the output lines for my module:

==> default: Notice: /Stage[main]/Bioperl/Exec[bioperl-download]/returns: executed successfully
==> default: Notice: /Stage[main]/Bioperl/Exec[bioperl-extract]/returns: executed successfully
==> default: Notice: /Stage[main]/Bioperl/Exec[bioperl-path]/returns: executed successfully

So all I know is it executed these three steps successfully. It doesn't tell me anything about whether the steps did their job properly or not. I know that it didn't download the archive to /usr/local/lib that directory, and that it didn't add an environment variable file to /usr/profile.d. Maybe the issue is the variables containing the directories are wrong. Maybe the variable containing the archives download URI is wrong. How can I find these things out?

UPDATE:

It turns out the module does work. But to improve the module (since I want to upload it to forge.puppetlabs.com, I tried implementing the changes suggested by Matt. Heres the new code:

  file { 'bioperl-download':
    path => "${archive_path}",
    source => "http://cpan.metacpan.org/authors/id/C/CJ/CJFIELDS/${archive_name}",
    ensure => "present"
  }

  exec { 'bioperl-extract':
    command => "sudo /bin/tar zxvf ${archive_name}",
    cwd => "${bioperl_target_dir}",
    require => File['bioperl-download']
  }

A problem: It gives me an error telling me that the source cannot be http://. I see in the docs that they do indeed allow http:// files as the source for the file resource. Maybe I'm using an older version of puppet?

I want to try out the puppet-archive module, but I'm not sure how I can set it as a required dependency. By that, I mean how I can make sure its installed first. Do I need to get my module to download the module from github and save it to the modules directory? Or is there a way to let puppet install it automatically? I added it as a dependency to the metadata.json file, but that doesn't install it. I know I can just get my module to download the package, but I was wondering what best practice for this is.

Upvotes: 1

Views: 1519

Answers (1)

Matthew Schuchard
Matthew Schuchard

Reputation: 28739

The initial problem you describe is acceptance testing. Verifying that the Puppet resources and code you wrote actually resulted in the desired end state you wanted is normally accomplished with Serverspec: http://serverspec.org/. For example, you can write a Puppet module to deploy an application, but you only know that Puppet did what you told it to, and not that the application actually successfully deployed. Note Serverspec is also what people generally use to solve this problem for Ansible and Chef also.

You can write a Serverspec test similar to the following to help test your module's end state:

describe file('/usr/local/lib/bioperl.tar.gz') do
  it { expect(subject).to be_file }
end

describe file('/usr/profile.d/env_file') do
  it { expect_subject).to be_file }
  its(:content) { is_expected.to match(/env stuff/) }
end

However, your problem also seems to deal with debugging why your acceptance tests failed. For that, you need unit testing. This is normally solved with RSpec-Puppet: http://rspec-puppet.com/. I would show you how to write some tests for your situation, but I don't think you should be writing your Puppet module the way that you did, so it would render the unit tests irrelevant.

Instead, consider using a file resource with the source attribute and a HTTP URI to grab the tarball instead of an exec with wget: https://docs.puppet.com/puppet/latest/type.html#file-attribute-source. Also, you might want to consider using the Puppet archive module to assist you: https://forge.puppet.com/puppet/archive.

If you have questions on how to use these tools to provide unit and acceptance testing, or have questions on how to refactor your module, then don't hesitate to write followup questions on StackOverflow and we can help you.

Upvotes: 1

Related Questions