Migrating to Puppet 3.x

I am a bit late to the Puppet 3.0 party, since 3.1 have been released recently1. After reading the release notes and “The Angry Guide to Puppet 3”, I thought most of the upgrade issues have been covered, but there was still a small surprise when it comes to types and providers.

The Exec resource had a small behavior change noted as: “Due to misleading values, the HOME and USER environment variables are now unset when running commands.”

The impact is a bit more significant than updating Exec resource since it also affects commands declared in providers. If the invoked command depends on the HOME environment variables such as brew, it will fail in Puppet 3:

Error: /Stage[main]//Package[rbenv]:
Could not evaluate: Could not list packages:
Execution of '/usr/local/bin/brew list --versions rbenv' returned 1:
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/pathname.rb:853:in `expand_path':
couldn't find HOME environment -- expanding `~/Library/Caches/Homebrew' (ArgumentError)
from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/pathname.rb:853:in `expand_path'
from /usr/local/Library/Homebrew/global.rb:22:in `cache'
from /usr/local/Library/Homebrew/global.rb:41
from /usr/local/bin/brew:17:in `require'
from /usr/local/bin/brew:17

The solution is described in #16779:

Setting command environment variables16779
1
2
3
has_command(:brew, 'brew') do
  environment({ 'HOME' => ENV['HOME'] })
end

The method ‘has_command’ is not backwards compatible with Puppet 2.x, so we need to wrap it around some version check:

1
2
3
4
5
6
7
8
9
if Puppet::Util::Package.versioncmp(Puppet.version, '3.0') >= 0
  has_command(:brew, "/usr/local/bin/brew") do
    environment({ 'HOME' => ENV['HOME'] })
  end
else
  commands :brew => "/usr/local/bin/brew"
end

brew('list', '--versions')

This also means execute will strip these two environment variables as well, so commands pass :custom_environment to preserve this value. execute is less common, and don’t use it unless you need special behavior such as :failonfail => false:

1
execute([command(:brew), 'list', '--version'], :custom_environment => {'HOME'=>ENV['HOME']})

Hope this is helpful for anyone else who stumbles into this issue.

  1. The proliferation of versions might be alarming, but it’s due to stricter adherence to semantic versioning. The changes 3.0 3.1 is closer to 2.7.0 to 2.7.1 than 2.6 to 2.7.