external_node_v2.rb weirdness with Rubygems 2.7.3 #611
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.