From afd22ddc99af306aa476be7eaf9f02ada941c97b Mon Sep 17 00:00:00 2001 From: Jeff McCune Date: Tue, 28 Feb 2012 11:01:15 -0800 Subject: (#12357) Fix root_home fact on Windows Without this patch the root_home fact fails on windows. This patch fixes the problem by only calling methods on the object returned by the `getent passwd root` command if the object evaluates to true. Because there is no root account on Windows the code block simply returns `nil` which makes the Facter fact undefined on Windows platforms. The root cause of the failure is that we always expected the command to succeed and return something useful, and it may not on all supported platforms. --- lib/facter/root_home.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib') 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 -- cgit v1.2.3 From a452f6a9af21d9ec5f34e6cda40af0ec3971b422 Mon Sep 17 00:00:00 2001 From: Jeff McCune Date: Wed, 29 Feb 2012 12:47:08 -0800 Subject: (#12357) Add puppet_vardir custom fact Without this patch the PE modules don't have a way to identify a filesystem path where it's OK to place variable data related to managing the target node. This is a problem when a module like pe_compliance needs to write a wrapper script to the node's filesystem. This patch addresses the problem by exposing the node's Puppet[:vardir] setting as a Facter fact. This fact value will be set to `nil` if Puppet is not loaded into memory. If Puppet is loaded, e.g. using `facter --puppet` or using `puppet agent` or `puppet apply` then the fact will automatically set the value to Puppet[:vardir] The value of this setting is subject to Puppet's run_mode. This patch implements a new utility method in the standard library module named `Facter::Util::PuppetSettings.with_puppet`. The method accepts a block and will only invoke the block if the Puppet library is loaded into the Ruby process. If Puppet is not loaded, the method always returns nil. This makes it easy to define Facter facts that only give values if Puppet is loaded in memory. --- lib/facter/puppet_vardir.rb | 16 ++++++++++++++++ lib/facter/util/puppet_settings.rb | 17 +++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 lib/facter/puppet_vardir.rb create mode 100644 lib/facter/util/puppet_settings.rb (limited to 'lib') diff --git a/lib/facter/puppet_vardir.rb b/lib/facter/puppet_vardir.rb new file mode 100644 index 0000000..755e33c --- /dev/null +++ b/lib/facter/puppet_vardir.rb @@ -0,0 +1,16 @@ +# 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. +require 'facter/util/puppet_settings' + +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/util/puppet_settings.rb b/lib/facter/util/puppet_settings.rb new file mode 100644 index 0000000..c8c8363 --- /dev/null +++ b/lib/facter/util/puppet_settings.rb @@ -0,0 +1,17 @@ +module Facter + module Util + module PuppetSettings + class << self + def with_puppet + begin + Module.const_get("Puppet") + rescue NameError + nil + else + yield + end + end + end + end + end +end -- cgit v1.2.3 From 369f7304310f8cff7d3c0cb81932aa8be1488ac2 Mon Sep 17 00:00:00 2001 From: Jeff McCune Date: Tue, 28 Feb 2012 11:53:15 -0800 Subject: (#12357) Make facter_dot_d look in Puppet[:confdir]/facts.d On Windows, we have no folders that match up to the default set of directories the facter_dot_d fact looks in by default. This is a problem because the Puppet Enterprise installer writes out the following facts by default, and our modules require them to be present: % cat /etc/puppetlabs/facter/facts.d/puppet_enterprise_installer.txt fact_stomp_port=61613 fact_stomp_server=puppetmaster fact_is_puppetagent=true fact_is_puppetmaster=true fact_is_puppetconsole=true On windows, the Puppet confdir is quite variable. On 2003 systems we default to the All Users application data directory. On 2008 systems we default to the ProgramData directory. The actual configuration directory varies depending on the Puppet or Puppet Enterprise branding. In order to simplify all of this variable behavior, this patch fixes the problem by automatically looking for facts in `%COMMON_APPDATA%/PuppetLabs/facter/facts.d` This patch paves the way for the MSI installer to use an IniFile element to write custom facts during installation. --- lib/facter/facter_dot_d.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'lib') diff --git a/lib/facter/facter_dot_d.rb b/lib/facter/facter_dot_d.rb index b94aacd..8543c7c 100644 --- a/lib/facter/facter_dot_d.rb +++ b/lib/facter/facter_dot_d.rb @@ -11,6 +11,9 @@ # 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 + +require 'facter/util/puppet_settings' + class Facter::Util::DotD require 'yaml' @@ -182,3 +185,10 @@ end 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 -- cgit v1.2.3 From 2ce669c7f8aea6b66b2150798a5ef4d253b00a2e Mon Sep 17 00:00:00 2001 From: Jeff McCune Date: Wed, 7 Mar 2012 11:52:30 -0800 Subject: (#12357) Add validate_absolute_path() function This patch adds a new function to validate if a string is an absolute filesystem path or not. The intent of this is to make this functionality generic and reusable. Josh left a comment in another pull request I had: If node_installdir or $node_vardir is not defined, then we should raise an error, otherwise we may create a scheduled task to an untrusted directory. One solution to this comment is to validate the Puppet variable is an absolute path. Examples of this function look like: function_validate_absolute_path Using Puppet::Parser::Scope.new Garbage inputs validate_absolute_path(nil) should fail validate_absolute_path([nil]) should fail validate_absolute_path({"foo"=>"bar"}) should fail validate_absolute_path({}) should fail validate_absolute_path("") should fail relative paths validate_absolute_path("relative1") should fail validate_absolute_path(".") should fail validate_absolute_path("..") should fail validate_absolute_path("./foo") should fail validate_absolute_path("../foo") should fail validate_absolute_path("etc/puppetlabs/puppet") should fail validate_absolute_path("opt/puppet/bin") should fail absolute paths validate_absolute_path("C:/") should not fail validate_absolute_path("C:\\") should not fail validate_absolute_path("C:\\WINDOWS\\System32") should not fail validate_absolute_path("C:/windows/system32") should not fail validate_absolute_path("X:/foo/bar") should not fail validate_absolute_path("X:\\foo\\bar") should not fail validate_absolute_path("/var/tmp") should not fail validate_absolute_path("/var/lib/puppet") should not fail validate_absolute_path("/var/opt/../lib/puppet") should not fail validate_absolute_path("C:\\Program Files (x86)\\Puppet Labs\\Puppet Enterprise") should not fail validate_absolute_path("C:/Program Files (x86)/Puppet Labs/Puppet Enterprise") should not fail Finished in 0.05637 seconds 23 examples, 0 failures --- .../parser/functions/validate_absolute_path.rb | 38 ++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 lib/puppet/parser/functions/validate_absolute_path.rb (limited to 'lib') diff --git a/lib/puppet/parser/functions/validate_absolute_path.rb b/lib/puppet/parser/functions/validate_absolute_path.rb new file mode 100644 index 0000000..46f86ec --- /dev/null +++ b/lib/puppet/parser/functions/validate_absolute_path.rb @@ -0,0 +1,38 @@ +module Puppet::Parser::Functions + newfunction(:validate_absolute_path, :doc => <<-'ENDHEREDOC') do |args| + Validate the string represents an absolute path in the filesystem. This function works + for windows and unix style paths. + + The following values will pass: + + $my_path = "C:/Program Files (x86)/Puppet Labs/Puppet" + validate_absolute_path($my_path) + $my_path2 = "/var/lib/puppet" + validate_absolute_path($my_path2) + + + The following values will fail, causing compilation to abort: + + validate_absolute_path(true) + validate_absolute_path([ 'var/lib/puppet', '/var/foo' ]) + validate_absolute_path([ '/var/lib/puppet', 'var/foo' ]) + $undefined = undef + validate_absolute_path($undefined) + + ENDHEREDOC + + require 'puppet/util' + + unless args.length > 0 then + raise Puppet::ParseError, ("validate_absolute_path(): wrong number of arguments (#{args.length}; must be > 0)") + end + + args.each do |arg| + # This logic was borrowed from + # [lib/puppet/file_serving/base.rb](https://github.com/puppetlabs/puppet/blob/master/lib/puppet/file_serving/base.rb) + unless Puppet::Util.absolute_path?(arg, :posix) or Puppet::Util.absolute_path?(arg, :windows) + raise Puppet::ParseError, ("#{arg.inspect} is not an absolute path.") + end + end + end +end -- cgit v1.2.3 From 41b07232e464f25403a8f9c786ec0061bf6dc40e Mon Sep 17 00:00:00 2001 From: Jeff McCune Date: Wed, 7 Mar 2012 15:01:11 -0800 Subject: (#12357) Add ability to display an error message from validate_re I've seen a number of times the following error displayed to the end user: validate_re(): "" does not match "^true$|^false$" at /p/t/f.pp:40 This is an absolutely horrific error message. I'm to blame for it. Users stumble over this quite often and they shouldn't have to go read the code to sort out what's happening. This patch makes an effort to fix the problem by adding a third, optional, argument to validate_re(). This third argument will be the message thrown back in the exception which will be displayed to the end user. This sets the stage for nicer error messages coming from modules we write. This patch is backwards compatible but is a new feature. --- lib/puppet/parser/functions/validate_re.rb | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/puppet/parser/functions/validate_re.rb b/lib/puppet/parser/functions/validate_re.rb index 8033ca3..9c216d8 100644 --- a/lib/puppet/parser/functions/validate_re.rb +++ b/lib/puppet/parser/functions/validate_re.rb @@ -1,5 +1,4 @@ module Puppet::Parser::Functions - newfunction(:validate_re, :doc => <<-'ENDHEREDOC') do |args| Perform simple validation of a string against one or more regular expressions. The first argument of this function should be a string to @@ -8,6 +7,9 @@ module Puppet::Parser::Functions of the regular expressions match the string passed in, compilation will abort with a parse error. + If a third argument is specified, this will be the error message raised and + seen by the user. + The following strings will validate against the regular expressions: validate_re('one', '^one$') @@ -17,17 +19,20 @@ module Puppet::Parser::Functions validate_re('one', [ '^two', '^three' ]) + A helpful error message can be returned like this: + + validate_re($::puppetversion, '^2.7', 'The $puppetversion fact value does not match 2.7') + ENDHEREDOC - if args.length != 2 then - raise Puppet::ParseError, ("validate_re(): wrong number of arguments (#{args.length}; must be 2)") + if (args.length < 2) or (args.length > 3) then + raise Puppet::ParseError, ("validate_re(): wrong number of arguments (#{args.length}; must be 2 or 3)") end - msg = "validate_re(): #{args[0].inspect} does not match #{args[1].inspect}" + msg = args[2] || "validate_re(): #{args[0].inspect} does not match #{args[1].inspect}" raise Puppet::ParseError, (msg) unless args[1].any? do |re_str| args[0] =~ Regexp.compile(re_str) end end - end -- cgit v1.2.3 From 010fb5e5685fec7aefe9e62901ebcdf06af19d5a Mon Sep 17 00:00:00 2001 From: Ken Barber Date: Wed, 7 Mar 2012 19:55:21 -0800 Subject: (#13018) Fix missing method any? message for ruby 1.9.x The any? method doesn't exist for 1.9.x, this converts a string to a single element array to work around the problem. --- lib/puppet/parser/functions/validate_re.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/puppet/parser/functions/validate_re.rb b/lib/puppet/parser/functions/validate_re.rb index 9c216d8..b5e8ff4 100644 --- a/lib/puppet/parser/functions/validate_re.rb +++ b/lib/puppet/parser/functions/validate_re.rb @@ -30,7 +30,7 @@ module Puppet::Parser::Functions msg = args[2] || "validate_re(): #{args[0].inspect} does not match #{args[1].inspect}" - raise Puppet::ParseError, (msg) unless args[1].any? do |re_str| + raise Puppet::ParseError, (msg) unless [args[1]].flatten.any? do |re_str| args[0] =~ Regexp.compile(re_str) end -- cgit v1.2.3 From f156e554d43f7d5517d2fd79bab41f7d9ee73688 Mon Sep 17 00:00:00 2001 From: Jeff McCune Date: Fri, 9 Mar 2012 14:08:54 -0800 Subject: (maint) Comment Ken's fix to String#any? Just added a comment about why we're doing what we're doing. --- lib/puppet/parser/functions/validate_re.rb | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/puppet/parser/functions/validate_re.rb b/lib/puppet/parser/functions/validate_re.rb index b5e8ff4..ca25a70 100644 --- a/lib/puppet/parser/functions/validate_re.rb +++ b/lib/puppet/parser/functions/validate_re.rb @@ -30,6 +30,8 @@ module Puppet::Parser::Functions msg = args[2] || "validate_re(): #{args[0].inspect} does not match #{args[1].inspect}" + # We're using a flattened array here because we can't call String#any? in + # Ruby 1.9 like we can in Ruby 1.8 raise Puppet::ParseError, (msg) unless [args[1]].flatten.any? do |re_str| args[0] =~ Regexp.compile(re_str) end -- cgit v1.2.3 From 31944c986345a135a3e68247c6d3e644ea369089 Mon Sep 17 00:00:00 2001 From: Jeff McCune Date: Mon, 12 Mar 2012 15:53:02 -0700 Subject: (#12357) Fix broken compatibility with Puppet 2.6 Without this patch, the previous change set to the validate_absolute_path() parser function contains Puppet 2.6 incompatible changes. stdlib 2.x is compatible with Puppet 2.6. These changes are a problem because we cannot introduce backwards incompatible changes in a minor release. This patch fixes the problem by back porting the implementation of the `Puppet::Util.absolute_path?` from 2.7.x to the function block itself. The function block tests to see if `Puppet::Util.absolute_path?` will respond and if not, falls back to the inline back ported implementation. The spec tests have been updated to simulate the behavior of Puppet 2.6 even when running with Puppet 2.7. --- .../parser/functions/validate_absolute_path.rb | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/puppet/parser/functions/validate_absolute_path.rb b/lib/puppet/parser/functions/validate_absolute_path.rb index 46f86ec..fe27974 100644 --- a/lib/puppet/parser/functions/validate_absolute_path.rb +++ b/lib/puppet/parser/functions/validate_absolute_path.rb @@ -30,8 +30,26 @@ module Puppet::Parser::Functions args.each do |arg| # This logic was borrowed from # [lib/puppet/file_serving/base.rb](https://github.com/puppetlabs/puppet/blob/master/lib/puppet/file_serving/base.rb) - unless Puppet::Util.absolute_path?(arg, :posix) or Puppet::Util.absolute_path?(arg, :windows) - raise Puppet::ParseError, ("#{arg.inspect} is not an absolute path.") + + # Puppet 2.7 and beyond will have Puppet::Util.absolute_path? Fall back to a back-ported implementation otherwise. + if Puppet::Util.respond_to?(:absolute_path?) then + unless Puppet::Util.absolute_path?(arg, :posix) or Puppet::Util.absolute_path?(arg, :windows) + raise Puppet::ParseError, ("#{arg.inspect} is not an absolute path.") + end + else + # This code back-ported from 2.7.x's lib/puppet/util.rb Puppet::Util.absolute_path? + # Determine in a platform-specific way whether a path is absolute. This + # defaults to the local platform if none is specified. + # Escape once for the string literal, and once for the regex. + slash = '[\\\\/]' + name = '[^\\\\/]+' + regexes = { + :windows => %r!^(([A-Z]:#{slash})|(#{slash}#{slash}#{name}#{slash}#{name})|(#{slash}#{slash}\?#{slash}#{name}))!i, + :posix => %r!^/!, + } + + rval = (!!(arg =~ regexes[:posix])) || (!!(arg =~ regexes[:windows])) + rval or raise Puppet::ParseError, ("#{arg.inspect} is not an absolute path.") end end end -- cgit v1.2.3