Uploaded image for project: 'Puppet'
  1. Puppet
  2. PUP-10731

Setting facterng twice raises an exception

    XMLWordPrintable

    Details

    • Type: CI Blocker
    • Status: Resolved
    • Priority: Normal
    • Resolution: Fixed
    • Affects Version/s: None
    • Fix Version/s: PUP 6.20.0
    • Component/s: None
    • Labels:
    • CI Pipeline/s:
      platform puppet-agent suite
    • Team:
      Night's Watch
    • Sub-team:
    • Sprint:
      ghost-4.11
    • Release Notes:
      Bug Fix
    • Release Notes Summary:
      Calling "puppet config set facterng true" twice would result in a failure. Now facterng is only enabled if it isn't already.
    • QA Risk Assessment:
      Needs Assessment

      Description

      Using 6.19.0, setting facterng to true twice programmatically results in a NameError:

      [root@baneful-extreme ~]# /opt/puppetlabs/puppet/bin/irb
      irb(main):001:0> require 'puppet'
      => true
      irb(main):002:0> Puppet.initialize_settings
      => {}
      irb(main):003:0> pp $LOADED_FEATURES.sort.grep /facter(-ng)?\.rb$/
      ["/opt/puppetlabs/puppet/lib/ruby/gems/2.5.0/gems/did_you_mean-1.2.0/lib/facter.rb",
       "/opt/puppetlabs/puppet/lib/ruby/vendor_ruby/facter.rb"]
      => ["/opt/puppetlabs/puppet/lib/ruby/gems/2.5.0/gems/did_you_mean-1.2.0/lib/facter.rb", "/opt/puppetlabs/puppet/lib/ruby/vendor_ruby/facter.rb"]
      irb(main):004:0> Puppet[:facterng] = true
      => true
      irb(main):005:0> pp $LOADED_FEATURES.sort.grep /facter(-ng)?\.rb$/
      ["/opt/puppetlabs/puppet/lib/ruby/gems/2.5.0/gems/did_you_mean-1.2.0/lib/facter.rb",
       "/opt/puppetlabs/puppet/lib/ruby/gems/2.5.0/gems/facter-ng-4.0.43/agent/lib/facter-ng.rb",
       "/opt/puppetlabs/puppet/lib/ruby/gems/2.5.0/gems/facter-ng-4.0.43/lib/facter.rb",
       "/opt/puppetlabs/puppet/lib/ruby/gems/2.5.0/gems/facter-ng-4.0.43/lib/facter/custom_facts/core/legacy_facter.rb",
       "/opt/puppetlabs/puppet/lib/ruby/vendor_ruby/facter.rb"]
      => ["/opt/puppetlabs/puppet/lib/ruby/gems/2.5.0/gems/did_you_mean-1.2.0/lib/facter.rb", "/opt/puppetlabs/puppet/lib/ruby/gems/2.5.0/gems/facter-ng-4.0.43/agent/lib/facter-ng.rb", "/opt/puppetlabs/puppet/lib/ruby/gems/2.5.0/gems/facter-ng-4.0.43/lib/facter.rb", "/opt/puppetlabs/puppet/lib/ruby/gems/2.5.0/gems/facter-ng-4.0.43/lib/facter/custom_facts/core/legacy_facter.rb", "/opt/puppetlabs/puppet/lib/ruby/vendor_ruby/facter.rb"]
      irb(main):006:0> Puppet[:facterng] = true
      Traceback (most recent call last):
              7: from /opt/puppetlabs/puppet/bin/irb:11:in `<main>'
              6: from (irb):6
              5: from /opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet.rb:108:in `[]='
              4: from /opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/settings.rb:178:in `[]='
              3: from /opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/settings.rb:1494:in `set'
              2: from /opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/defaults.rb:87:in `block in initialize_default_settings!'
              1: from /opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/util/logging.rb:258:in `setup_facter_logging!'
      NameError (uninitialized constant Puppet::Util::Logging::Facter)
      Did you mean?  Facts
      

      The first time Puppet[:facterng] = true is called, the hook for the setting calls require 'facter-ng' and ruby adds it to the special $LOADED_FEATURES hash. The next time Puppet[:facterng] = true is called, we remove the Facter constant and then we try to require 'facter-ng' again. But ruby "remembers" that it already required it once, and doesn't require it again. As a result, require 'facter-ng' returns false, and the Facter constant is not defined when we call into:

        def self.setup_facter_logging!
          # Only recent versions of Facter support this feature
          return false unless Facter.respond_to? :on_message
      ...
      

      We then get a NameError trying to call Facter.respond_to?.

      We may want to define the hook in such a way that if facterng is already enabled, we don't try to enable it a second time. The difficulty is when the hook is called, the new value is already "set", so AFAIK you can't ask for the previous value.

      Alternative, you can call Kernel.load <path> to force facter-ng to be reloaded. But you need to specify a full path to the file and that might be hard when running as a gem or from packages.

      Also a few things I noticed:

      • The hook needs to munge the value passed to it, as it may receive the string "false" which is truthy. This can occur when called programmatically or via puppet config set facterng false.
      • After calling require/load 'facter-ng' It would also be good to check that the Facter constant is defined before calling into setup_facter_logging!.

        Attachments

          Activity

            People

            Assignee:
            Unassigned Unassigned
            Reporter:
            josh Josh Cooper
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Dates

              Created:
              Updated:
              Resolved:

                Zendesk Support