Description
Something changed sometime between Rubygems 2.4.5 and 2.7.3 in the way require
works with regards to the current working directory. This leads to the following error when running external_node_v2.rb --push-facts
when the current working directory is /root
under Rubygems 2.7.3:
Could not generate facts for Foreman: Permission denied @ dir_chdir - /root
This is usually the case when the external_node_v2.rb
script is started from Cron. We run Puppet 5 so the facter
Gem is usually not available in the regular, system-wide Ruby/Gem environment. The script trips up when trying to require 'facter'
; this should normally fail with a LoadError
that is then rescued, but another exception from rubygems/util.rb
occurs (with the above error message) that is not rescued.
Here is a test script with the relevant parts external_node_v2.rb
from that reproduces the problem:
#!/usr/bin/env ruby
require 'etc'
puppetuser = 'puppet'
begin
Process::GID.change_privilege(Etc.getgrnam(puppetuser).gid) unless Etc.getpwuid.name == puppetuser
Process::UID.change_privilege(Etc.getpwnam(puppetuser).uid) unless Etc.getpwuid.name == puppetuser
# Facter (in thread_count) tries to read from $HOME, which is still /root after the UID change
ENV['HOME'] = Etc.getpwnam(puppetuser).dir
rescue
$stderr.puts "cannot switch to user #{puppetuser}, continuing as '#{Etc.getpwuid.name}'"
end
begin
require 'facter'
puts "facter: " + Facter.value(:fqdn).to_s
rescue LoadError
puts "no facter: " + `hostname -f`.strip
end
Run this script as root with Rubygems 2.7.3 while residing in the /root
directory and the problem surfaces like this:
root@host01 [/root] # ./test.rb
/usr/local/lib/site_ruby/2.3.0/rubygems/util.rb:117:in `chdir': Permission denied @ dir_chdir - /root (Errno::EACCES)
from /usr/local/lib/site_ruby/2.3.0/rubygems/util.rb:117:in `block in traverse_parents'
from /usr/local/lib/site_ruby/2.3.0/rubygems/util.rb:116:in `loop'
from /usr/local/lib/site_ruby/2.3.0/rubygems/util.rb:116:in `traverse_parents'
from /usr/local/lib/site_ruby/2.3.0/rubygems/bundler_version_finder.rb:93:in `lockfile_contents'
from /usr/local/lib/site_ruby/2.3.0/rubygems/bundler_version_finder.rb:81:in `lockfile_version'
from /usr/local/lib/site_ruby/2.3.0/rubygems/bundler_version_finder.rb:29:in `bundler_version_with_reason'
from /usr/local/lib/site_ruby/2.3.0/rubygems/bundler_version_finder.rb:12:in `bundler_version'
from /usr/local/lib/site_ruby/2.3.0/rubygems/bundler_version_finder.rb:46:in `compatible?'
from /usr/local/lib/site_ruby/2.3.0/rubygems/specification.rb:1059:in `block in find_by_path'
from /usr/local/lib/site_ruby/2.3.0/rubygems/specification.rb:1058:in `each'
from /usr/local/lib/site_ruby/2.3.0/rubygems/specification.rb:1058:in `find'
from /usr/local/lib/site_ruby/2.3.0/rubygems/specification.rb:1058:in `find_by_path'
from /usr/local/lib/site_ruby/2.3.0/rubygems.rb:213:in `try_activate'
from /usr/local/lib/site_ruby/2.3.0/rubygems/core_ext/kernel_require.rb:128:in `rescue in require'
from /usr/local/lib/site_ruby/2.3.0/rubygems/core_ext/kernel_require.rb:40:in `require'
from ./test.rb:15:in `<main>'
The problem does not occur with Rubygems 2.4.5. I haven't tested other versions yet.
I don't know if this is a bug in Rubygems that should be addressed there but external_node_v2.rb
can be fixed easily by adding the line Dir.chdir ENV['HOME']
after setting ENV['HOME']
. I think this should be done anyway, regardless of any change in Rubygems' behaviour, to be on the safe side.
I'll submit a PR for this.