[Pkg-puppet-devel] [facter] 68/352: (#22944) Don't execute external facts 19 times

Stig Sandbeck Mathisen ssm at debian.org
Sun Apr 6 22:21:32 UTC 2014


This is an automated email from the git hooks/post-receive script.

ssm pushed a commit to branch master
in repository facter.

commit ab999818f52519c579843c596db62af017b16b07
Author: Josh Cooper <josh at puppetlabs.com>
Date:   Thu Dec 5 22:10:11 2013 -0800

    (#22944) Don't execute external facts 19 times
    
    Previously, facter would load every external fact many, many times. For
    executable facts, e.g. powershell, this means executing the fact. For
    text based facts, it means reading the file, and parsing its output. On
    Darwin, it was common for facts to be executed 6 times; on Windows,
    19 times.
    
    The problem occurs whenever facter requires a file, e.g. `ec2.rb`, which
    references another fact, e.g. `:macaddress` outside the body of any
    resolution, and facter has not yet required `macaddress.rb`.
    
    For example, the following will cause all external facts to be loaded:
    
        if Facter.value(:macaddress)
          Facter.add(:ec2) do
            ...
          end
        end
    
    Note that this is triggered because macaddress comes after ec2.
    Similarly, `blockdevices.rb` references the `:kernel` fact outside of
    any resolution, so that's another round of external fact evaluation.
    
    This commit keeps adds a boolean flag to ensure we only execute external
    facts once.
---
 acceptance/tests/runs_external_facts_once.rb | 59 ++++++++++++++++++++++++++++
 lib/facter/util/collection.rb                | 11 +++++-
 2 files changed, 68 insertions(+), 2 deletions(-)

diff --git a/acceptance/tests/runs_external_facts_once.rb b/acceptance/tests/runs_external_facts_once.rb
new file mode 100644
index 0000000..afd6907
--- /dev/null
+++ b/acceptance/tests/runs_external_facts_once.rb
@@ -0,0 +1,59 @@
+test_name "#22944: Facter executes external executable facts many times"
+
+unix_content = <<EOM
+#!/bin/sh
+echo "SCRIPT CALLED" >&2
+echo "test=value"
+EOM
+
+win_content = <<EOM
+echo "SCRIPT CALLED" >&2
+echo "test=value"
+EOM
+
+agents.each do |agent|
+  step "Agent #{agent}: create external executable fact"
+
+  # assume we're running as root
+  if agent['platform'] =~ /windows/
+    if on(agent, facter('kernelmajversion')).stdout.chomp.to_f < 6.0
+      factsd = 'C:/Documents and Settings/All Users/Application Data/PuppetLabs/facter/facts.d'
+    else
+      factsd = 'C:/ProgramData/PuppetLabs/facter/facts.d'
+    end
+    ext = '.bat'
+    content = win_content
+  else
+    factsd = '/etc/facter/facts.d'
+    ext = '.sh'
+    content = unix_content
+  end
+
+
+  step "Agent #{agent}: create facts.d directory"
+  on(agent, "mkdir -p '#{factsd}'")
+
+
+  step "Agent #{agent}: create external fact"
+  ext_fact = "#{factsd}/external_fact#{ext}"
+
+  teardown do
+    on(agent, "rm -f '#{ext_fact}'")
+  end
+
+  create_remote_file(agent, ext_fact, content)
+
+  step "Agent #{agent}: make it executable"
+  on(agent, "chmod +x '#{ext_fact}'")
+
+  step "Agent #{agent}: ensure it only executes once"
+  on(agent, facter) do
+    lines = stderr.split('\n')
+    times = lines.count { |line| line =~ /SCRIPT CALLED/ }
+    if times == 1
+      step "External executable fact executed once"
+    else
+      fail_test "External fact executed #{times} times, expected once: #{stderr}"
+    end
+  end
+end
diff --git a/lib/facter/util/collection.rb b/lib/facter/util/collection.rb
index 7c02ce0..4b91e10 100644
--- a/lib/facter/util/collection.rb
+++ b/lib/facter/util/collection.rb
@@ -106,13 +106,13 @@ class Facter::Util::Collection
 
   def load(name)
     internal_loader.load(name)
-    external_loader.load(self)
+    load_external_facts
   end
 
   # Load all known facts.
   def load_all
     internal_loader.load_all
-    external_loader.load(self)
+    load_external_facts
   end
 
   def internal_loader
@@ -146,4 +146,11 @@ class Facter::Util::Collection
   def canonicalize(name)
     name.to_s.downcase.to_sym
   end
+
+  def load_external_facts
+    if ! @external_facts_loaded
+      @external_facts_loaded = true
+      external_loader.load(self)
+    end
+  end
 end

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-puppet/facter.git



More information about the Pkg-puppet-devel mailing list