diff options
Diffstat (limited to 'lib/facter')
-rw-r--r-- | lib/facter/facter_dot_d.rb | 287 | ||||
-rw-r--r-- | lib/facter/pe_version.rb | 53 | ||||
-rw-r--r-- | lib/facter/puppet_vardir.rb | 26 | ||||
-rw-r--r-- | lib/facter/root_home.rb | 4 | ||||
-rw-r--r-- | lib/facter/util/puppet_settings.rb | 21 |
5 files changed, 256 insertions, 135 deletions
diff --git a/lib/facter/facter_dot_d.rb b/lib/facter/facter_dot_d.rb index 90586a9..e414b20 100644 --- a/lib/facter/facter_dot_d.rb +++ b/lib/facter/facter_dot_d.rb @@ -1,4 +1,5 @@ -# A Facter plugin that loads facts from /etc/facts.d. +# A Facter plugin that loads facts from /etc/facter/facts.d +# and /etc/puppetlabs/facter/facts.d. # # Facts can be in the form of JSON, YAML or Text files # and any executable that returns key=value pairs. @@ -10,174 +11,192 @@ # The cache is stored in /tmp/facts_cache.yaml as a mode # 600 file and will have the end result of not calling your # fact scripts more often than is needed + class Facter::Util::DotD - require 'yaml' + require 'yaml' - def initialize(dir="/etc/facts.d", cache_file="/tmp/facts_cache.yml") - @dir = dir - @cache_file = cache_file - @cache = nil - @types = {".txt" => :txt, ".json" => :json, ".yaml" => :yaml} - end + def initialize(dir="/etc/facts.d", cache_file="/tmp/facts_cache.yml") + @dir = dir + @cache_file = cache_file + @cache = nil + @types = {".txt" => :txt, ".json" => :json, ".yaml" => :yaml} + end - def entries - Dir.entries(@dir).reject{|f| f =~ /^\.|\.ttl$/}.sort.map {|f| File.join(@dir, f) } - rescue - [] - end + def entries + Dir.entries(@dir).reject{|f| f =~ /^\.|\.ttl$/}.sort.map {|f| File.join(@dir, f) } + rescue + [] + end - def fact_type(file) - extension = File.extname(file) + def fact_type(file) + extension = File.extname(file) - type = @types[extension] || :unknown + type = @types[extension] || :unknown - type = :script if type == :unknown && File.executable?(file) + type = :script if type == :unknown && File.executable?(file) - return type - end + return type + end - def txt_parser(file) - File.readlines(file).each do |line| - if line =~ /^(.+)=(.+)$/ - var = $1; val = $2 + def txt_parser(file) + File.readlines(file).each do |line| + if line =~ /^(.+)=(.+)$/ + var = $1; val = $2 - Facter.add(var) do - setcode { val } - end - end + Facter.add(var) do + setcode { val } end - rescue Exception => e - Facter.warn("Failed to handle #{file} as text facts: #{e.class}: #{e}") + end end - - def json_parser(file) - begin - require 'json' - rescue LoadError - require 'rubygems' - retry - end - - JSON.load(File.read(file)).each_pair do |f, v| - Facter.add(f) do - setcode { v } - end - end - rescue Exception => e - Facter.warn("Failed to handle #{file} as json facts: #{e.class}: #{e}") + rescue Exception => e + Facter.warn("Failed to handle #{file} as text facts: #{e.class}: #{e}") + end + + def json_parser(file) + begin + require 'json' + rescue LoadError + retry if require 'rubygems' + raise end - def yaml_parser(file) - require 'yaml' - - YAML.load_file(file).each_pair do |f, v| - Facter.add(f) do - setcode { v } - end - end - rescue Exception => e - Facter.warn("Failed to handle #{file} as yaml facts: #{e.class}: #{e}") + JSON.load(File.read(file)).each_pair do |f, v| + Facter.add(f) do + setcode { v } + end end + rescue Exception => e + Facter.warn("Failed to handle #{file} as json facts: #{e.class}: #{e}") + end - def script_parser(file) - result = cache_lookup(file) - ttl = cache_time(file) - - unless result - result = Facter::Util::Resolution.exec(file) + def yaml_parser(file) + require 'yaml' - if ttl > 0 - Facter.debug("Updating cache for #{file}") - cache_store(file, result) - cache_save! - end - else - Facter.debug("Using cached data for #{file}") - end + YAML.load_file(file).each_pair do |f, v| + Facter.add(f) do + setcode { v } + end + end + rescue Exception => e + Facter.warn("Failed to handle #{file} as yaml facts: #{e.class}: #{e}") + end + + def script_parser(file) + result = cache_lookup(file) + ttl = cache_time(file) + + unless result + result = Facter::Util::Resolution.exec(file) + + if ttl > 0 + Facter.debug("Updating cache for #{file}") + cache_store(file, result) + cache_save! + end + else + Facter.debug("Using cached data for #{file}") + end - result.split("\n").each do |line| - if line =~ /^(.+)=(.+)$/ - var = $1; val = $2 + result.split("\n").each do |line| + if line =~ /^(.+)=(.+)$/ + var = $1; val = $2 - Facter.add(var) do - setcode { val } - end - end + Facter.add(var) do + setcode { val } end - rescue Exception => e - Facter.warn("Failed to handle #{file} as script facts: #{e.class}: #{e}") - Facter.debug(e.backtrace.join("\n\t")) + end end + rescue Exception => e + Facter.warn("Failed to handle #{file} as script facts: #{e.class}: #{e}") + Facter.debug(e.backtrace.join("\n\t")) + end - def cache_save! - cache = load_cache - File.open(@cache_file, "w", 0600) {|f| f.write(YAML.dump(cache)) } - rescue - end + def cache_save! + cache = load_cache + File.open(@cache_file, "w", 0600) {|f| f.write(YAML.dump(cache)) } + rescue + end - def cache_store(file, data) - load_cache + def cache_store(file, data) + load_cache - @cache[file] = {:data => data, :stored => Time.now.to_i} - rescue - end + @cache[file] = {:data => data, :stored => Time.now.to_i} + rescue + end - def cache_lookup(file) - cache = load_cache + def cache_lookup(file) + cache = load_cache - return nil if cache.empty? + return nil if cache.empty? - ttl = cache_time(file) + ttl = cache_time(file) - if cache[file] - now = Time.now.to_i + if cache[file] + now = Time.now.to_i - return cache[file][:data] if ttl == -1 - return cache[file][:data] if (now - cache[file][:stored]) <= ttl - return nil - else - return nil - end - rescue - return nil + return cache[file][:data] if ttl == -1 + return cache[file][:data] if (now - cache[file][:stored]) <= ttl + return nil + else + return nil + end + rescue + return nil + end + + def cache_time(file) + meta = file + ".ttl" + + return File.read(meta).chomp.to_i + rescue + return 0 + end + + def load_cache + unless @cache + if File.exist?(@cache_file) + @cache = YAML.load_file(@cache_file) + else + @cache = {} + end end - def cache_time(file) - meta = file + ".ttl" + return @cache + rescue + @cache = {} + return @cache + end - return File.read(meta).chomp.to_i - rescue - return 0 - end + def create + entries.each do |fact| + type = fact_type(fact) + parser = "#{type}_parser" - def load_cache - unless @cache - if File.exist?(@cache_file) - @cache = YAML.load_file(@cache_file) - else - @cache = {} - end - end + if respond_to?("#{type}_parser") + Facter.debug("Parsing #{fact} using #{parser}") - return @cache - rescue - @cache = {} - return @cache + send(parser, fact) + end end + end +end - def create - entries.each do |fact| - type = fact_type(fact) - parser = "#{type}_parser" - - if respond_to?("#{type}_parser") - Facter.debug("Parsing #{fact} using #{parser}") - send(parser, fact) - end - end +mdata = Facter.version.match(/(\d+)\.(\d+)\.(\d+)/) +if mdata + (major, minor, patch) = mdata.captures.map { |v| v.to_i } + if major < 2 + # Facter 1.7 introduced external facts support directly + unless major == 1 and minor > 6 + Facter::Util::DotD.new("/etc/facter/facts.d").create + Facter::Util::DotD.new("/etc/puppetlabs/facter/facts.d").create + + # Windows has a different configuration directory that defaults to a vendor + # specific sub directory of the %COMMON_APPDATA% directory. + if Dir.const_defined? 'COMMON_APPDATA' then + windows_facts_dot_d = File.join(Dir::COMMON_APPDATA, 'PuppetLabs', 'facter', 'facts.d') + Facter::Util::DotD.new(windows_facts_dot_d).create + end end + end end - -Facter::Util::DotD.new("/etc/facter/facts.d").create -Facter::Util::DotD.new("/etc/puppetlabs/facter/facts.d").create diff --git a/lib/facter/pe_version.rb b/lib/facter/pe_version.rb new file mode 100644 index 0000000..0cc0f64 --- /dev/null +++ b/lib/facter/pe_version.rb @@ -0,0 +1,53 @@ +# Fact: is_pe, pe_version, pe_major_version, pe_minor_version, pe_patch_version +# +# Purpose: Return various facts about the PE state of the system +# +# Resolution: Uses a regex match against puppetversion to determine whether the +# machine has Puppet Enterprise installed, and what version (overall, major, +# minor, patch) is installed. +# +# Caveats: +# +Facter.add("pe_version") do + setcode do + pe_ver = Facter.value("puppetversion").match(/Puppet Enterprise (\d+\.\d+\.\d+)/) + pe_ver[1] if pe_ver + end +end + +Facter.add("is_pe") do + setcode do + if Facter.value(:pe_version).to_s.empty? then + false + else + true + end + end +end + +Facter.add("pe_major_version") do + confine :is_pe => true + setcode do + if pe_version = Facter.value(:pe_version) + pe_version.to_s.split('.')[0] + end + end +end + +Facter.add("pe_minor_version") do + confine :is_pe => true + setcode do + if pe_version = Facter.value(:pe_version) + pe_version.to_s.split('.')[1] + end + end +end + +Facter.add("pe_patch_version") do + confine :is_pe => true + setcode do + if pe_version = Facter.value(:pe_version) + pe_version.to_s.split('.')[2] + end + end +end diff --git a/lib/facter/puppet_vardir.rb b/lib/facter/puppet_vardir.rb new file mode 100644 index 0000000..0e6af40 --- /dev/null +++ b/lib/facter/puppet_vardir.rb @@ -0,0 +1,26 @@ +# This facter fact returns the value of the Puppet vardir setting for the node +# running puppet or puppet agent. The intent is to enable Puppet modules to +# automatically have insight into a place where they can place variable data, +# regardless of the node's platform. +# +# The value should be directly usable in a File resource path attribute. + + +begin + require 'facter/util/puppet_settings' +rescue LoadError => e + # puppet apply does not add module lib directories to the $LOAD_PATH (See + # #4248). It should (in the future) but for the time being we need to be + # defensive which is what this rescue block is doing. + rb_file = File.join(File.dirname(__FILE__), 'util', 'puppet_settings.rb') + load rb_file if File.exists?(rb_file) or raise e +end + +Facter.add(:puppet_vardir) do + setcode do + # This will be nil if Puppet is not available. + Facter::Util::PuppetSettings.with_puppet do + Puppet[:vardir] + end + end +end diff --git a/lib/facter/root_home.rb b/lib/facter/root_home.rb index 61fcf39..8249f7d 100644 --- a/lib/facter/root_home.rb +++ b/lib/facter/root_home.rb @@ -7,7 +7,9 @@ module Facter::Util::RootHome def get_root_home root_ent = Facter::Util::Resolution.exec("getent passwd root") # The home directory is the sixth element in the passwd entry - root_ent.split(":")[5] + # If the platform doesn't have getent, root_ent will be nil and we should + # return it straight away. + root_ent && root_ent.split(":")[5] end end end diff --git a/lib/facter/util/puppet_settings.rb b/lib/facter/util/puppet_settings.rb new file mode 100644 index 0000000..1ad9452 --- /dev/null +++ b/lib/facter/util/puppet_settings.rb @@ -0,0 +1,21 @@ +module Facter + module Util + module PuppetSettings + # This method is intended to provide a convenient way to evaluate a + # Facter code block only if Puppet is loaded. This is to account for the + # situation where the fact happens to be in the load path, but Puppet is + # not loaded for whatever reason. Perhaps the user is simply running + # facter without the --puppet flag and they happen to be working in a lib + # directory of a module. + def self.with_puppet + begin + Module.const_get("Puppet") + rescue NameError + nil + else + yield + end + end + end + end +end |