summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG7
-rw-r--r--Modulefile2
-rw-r--r--README_DEVELOPER.markdown35
-rw-r--r--RELEASE_PROCESS.markdown18
-rw-r--r--lib/facter/facter_dot_d.rb11
-rw-r--r--lib/facter/puppet_vardir.rb26
-rw-r--r--lib/facter/root_home.rb4
-rw-r--r--lib/facter/util/puppet_settings.rb21
-rw-r--r--lib/puppet/parser/functions/get_module_path.rb17
-rw-r--r--lib/puppet/parser/functions/str2saltedsha512.rb32
-rw-r--r--lib/puppet/parser/functions/validate_absolute_path.rb56
-rw-r--r--lib/puppet/parser/functions/validate_re.rb19
-rw-r--r--lib/puppet/parser/functions/validate_slength.rb52
-rw-r--r--lib/puppet/provider/file_line/ruby.rb14
-rw-r--r--lib/puppet/type/file_line.rb7
-rw-r--r--spec/spec_helper.rb2
-rw-r--r--spec/unit/facter/root_home_spec.rb12
-rw-r--r--spec/unit/facter/util/puppet_settings_spec.rb35
-rw-r--r--spec/unit/puppet/parser/functions/get_module_path_spec.rb42
-rw-r--r--spec/unit/puppet/parser/functions/str2saltedsha512_spec.rb51
-rw-r--r--spec/unit/puppet/parser/functions/validate_absolute_path_spec.rb83
-rw-r--r--spec/unit/puppet/parser/functions/validate_re_spec.rb80
-rwxr-xr-xspec/unit/puppet/parser/functions/validate_slength_spec.rb52
-rw-r--r--spec/unit/puppet/provider/file_line/ruby_spec.rb79
24 files changed, 708 insertions, 49 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 4fe3e28..f027d4e 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,6 +2,13 @@
* (#11607) Add Rakefile to enable spec testing
* (#12377) Avoid infinite loop when retrying require json
+2012-03-13 Puppet Labs <support@puppetlabs.com> - 2.3.1
+* (#13091) Fix LoadError bug with puppet apply and puppet_vardir fact
+
+2012-03-12 Puppet Labs <support@puppetlabs.com> - 2.3.0
+* Add a large number of new Puppet functions
+* Backwards compatibility preserved with 2.2.x
+
2011-12-30 Puppet Labs <support@puppetlabs.com> - 2.2.1
* Documentation only release for the Forge
diff --git a/Modulefile b/Modulefile
index 0be5723..a6874ce 100644
--- a/Modulefile
+++ b/Modulefile
@@ -1,5 +1,5 @@
name 'puppetlabs-stdlib'
-version '2.2.2'
+version '2.3.2'
source 'git://github.com/puppetlabs/puppetlabs-stdlib'
author 'puppetlabs'
license 'Apache 2.0'
diff --git a/README_DEVELOPER.markdown b/README_DEVELOPER.markdown
new file mode 100644
index 0000000..e8aa27a
--- /dev/null
+++ b/README_DEVELOPER.markdown
@@ -0,0 +1,35 @@
+Puppet Specific Facts
+=====================
+
+Facter is meant to stand alone and apart from Puppet. However, Facter often
+runs inside Puppet and all custom facts included in the stdlib module will
+almost always be evaluated in the context of Puppet and Facter working
+together.
+
+Still, we don't want to write custom facts that blow up in the users face if
+Puppet is not loaded in memory. This is often the case if the user run
+`facter` without also supplying the `--puppet` flag.
+
+Ah! But Jeff, the custom fact won't be in the `$LOAD_PATH` unless the user
+supplies `--facter`! You might say...
+
+Not (always) true I say! If the user happens to have a CWD of
+`<modulepath>/stdlib/lib` then the facts will automatically be evaluated and
+blow up.
+
+In any event, it's pretty easy to write a fact that has no value if Puppet is
+not loaded. Simply do it like this:
+
+ Facter.add(:node_vardir) do
+ setcode do
+ # This will be nil if Puppet is not available.
+ Facter::Util::PuppetSettings.with_puppet do
+ Puppet[:vardir]
+ end
+ end
+ end
+
+The `Facter::Util::PuppetSettings.with_puppet` method accepts a block and
+yields to it only if the Puppet library is loaded. If the Puppet library is
+not loaded, then the method silently returns `nil` which Facter interprets as
+an undefined fact value. The net effect is that the fact won't be set.
diff --git a/RELEASE_PROCESS.markdown b/RELEASE_PROCESS.markdown
index ea40d5d..3982c84 100644
--- a/RELEASE_PROCESS.markdown
+++ b/RELEASE_PROCESS.markdown
@@ -1,13 +1,25 @@
-# Releasing this module #
+# Contributing to this module #
* Work in a topic branch
* Submit a github pull request
* Address any comments / feeback
* Merge into master using --no-ff
+
+# Releasing this module #
+
+ * This module adheres to http://semver.org/
+ * Look for API breaking changes using git diff vX.Y.Z..master
+ * If no API breaking changes, the minor version may be bumped.
+ * If there are API breaking changes, the major version must be bumped.
+ * If there are only small minor changes, the patch version may be bumped.
* Update the CHANGELOG
* Update the Modulefile
- * Create an annotated tag with git tag -a X.Y.Z -m 'version X.Y.Z'
+ * Commit these changes with a message along the lines of "Update CHANGELOG and
+ Modulefile for release"
+ * Create an annotated tag with git tag -a vX.Y.Z -m 'version X.Y.Z' (NOTE the
+ leading v as per semver.org)
* Push the tag with git push origin --tags
- * Build a new package with puppet-module
+ * Build a new package with puppet-module or the rake build task if it exists
* Publish the new package to the forge
+ * Bonus points for an announcement to puppet-users.
diff --git a/lib/facter/facter_dot_d.rb b/lib/facter/facter_dot_d.rb
index 2658dfe..3e528ab 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,6 +11,7 @@
# 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'
@@ -181,3 +183,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
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
diff --git a/lib/puppet/parser/functions/get_module_path.rb b/lib/puppet/parser/functions/get_module_path.rb
new file mode 100644
index 0000000..4d2b50b
--- /dev/null
+++ b/lib/puppet/parser/functions/get_module_path.rb
@@ -0,0 +1,17 @@
+module Puppet::Parser::Functions
+ newfunction(:get_module_path, :type =>:rvalue, :doc => <<-EOT
+ Returns the absolute path of the specified module for the current
+ environment.
+
+ Example:
+ $module_path = get_module_path('stdlib')
+ EOT
+ ) do |args|
+ raise(Puppet::ParseError, "get_module_name(): Wrong number of arguments, expects one") unless args.size == 1
+ if module_path = Puppet::Module.find(args[0], compiler.environment.to_s)
+ module_path.path
+ else
+ raise(Puppet::ParseError, "Could not find module #{args[0]} in environment #{compiler.environment}")
+ end
+ end
+end
diff --git a/lib/puppet/parser/functions/str2saltedsha512.rb b/lib/puppet/parser/functions/str2saltedsha512.rb
new file mode 100644
index 0000000..7fe7b01
--- /dev/null
+++ b/lib/puppet/parser/functions/str2saltedsha512.rb
@@ -0,0 +1,32 @@
+#
+# str2saltedsha512.rb
+#
+
+module Puppet::Parser::Functions
+ newfunction(:str2saltedsha512, :type => :rvalue, :doc => <<-EOS
+This converts a string to a salted-SHA512 password hash (which is used for
+OS X versions >= 10.7). Given any simple string, you will get a hex version
+of a salted-SHA512 password hash that can be inserted into your Puppet
+manifests as a valid password attribute.
+ EOS
+ ) do |arguments|
+ require 'digest/sha2'
+
+ raise(Puppet::ParseError, "str2saltedsha512(): Wrong number of arguments " +
+ "passed (#{arguments.size} but we require 1)") if arguments.size != 1
+
+ password = arguments[0]
+
+ unless password.is_a?(String)
+ raise(Puppet::ParseError, 'str2saltedsha512(): Requires a ' +
+ "String argument, you passed: #{password.class}")
+ end
+
+ seedint = rand(2**31 - 1)
+ seedstring = Array(seedint).pack("L")
+ saltedpass = Digest::SHA512.digest(seedstring + password)
+ (seedstring + saltedpass).unpack('H*')[0]
+ end
+end
+
+# vim: set ts=2 sw=2 et :
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..fe27974
--- /dev/null
+++ b/lib/puppet/parser/functions/validate_absolute_path.rb
@@ -0,0 +1,56 @@
+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)
+
+ # 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
+end
diff --git a/lib/puppet/parser/functions/validate_re.rb b/lib/puppet/parser/functions/validate_re.rb
index 8033ca3..ca25a70 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,22 @@ 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|
+ # 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
end
-
end
diff --git a/lib/puppet/parser/functions/validate_slength.rb b/lib/puppet/parser/functions/validate_slength.rb
new file mode 100644
index 0000000..fdcc0a2
--- /dev/null
+++ b/lib/puppet/parser/functions/validate_slength.rb
@@ -0,0 +1,52 @@
+module Puppet::Parser::Functions
+
+ newfunction(:validate_slength, :doc => <<-'ENDHEREDOC') do |args|
+ Validate that the first argument is a string (or an array of strings), and
+ less/equal to than the length of the second argument. It fails if the first
+ argument is not a string or array of strings, and if arg 2 is not convertable
+ to a number.
+
+ The following values will pass:
+
+ validate_slength("discombobulate",17)
+ validate_slength(["discombobulate","moo"],17)
+
+ The following valueis will not:
+
+ validate_slength("discombobulate",1)
+ validate_slength(["discombobulate","thermometer"],5)
+
+ ENDHEREDOC
+
+ raise Puppet::ParseError, ("validate_slength(): Wrong number of arguments (#{args.length}; must be = 2)") unless args.length == 2
+
+ unless (args[0].is_a?(String) or args[0].is_a?(Array))
+ raise Puppet::ParseError, ("validate_slength(): please pass a string, or an array of strings - what you passed didn't work for me at all - #{args[0].class}")
+ end
+
+ begin
+ max_length = args[1].to_i
+ rescue NoMethodError => e
+ raise Puppet::ParseError, ("validate_slength(): Couldn't convert whatever you passed as the length parameter to an integer - sorry: " + e.message )
+ end
+
+ raise Puppet::ParseError, ("validate_slength(): please pass a positive number as max_length") unless max_length > 0
+
+ case args[0]
+ when String
+ raise Puppet::ParseError, ("validate_slength(): #{args[0].inspect} is #{args[0].length} characters. It should have been less than or equal to #{max_length} characters") unless args[0].length <= max_length
+ when Array
+ args[0].each do |arg|
+ if arg.is_a?(String)
+ unless ( arg.is_a?(String) and arg.length <= max_length )
+ raise Puppet::ParseError, ("validate_slength(): #{arg.inspect} is #{arg.length} characters. It should have been less than or equal to #{max_length} characters")
+ end
+ else
+ raise Puppet::ParseError, ("validate_slength(): #{arg.inspect} is not a string, it's a #{arg.class}")
+ end
+ end
+ else
+ raise Puppet::ParseError, ("validate_slength(): please pass a string, or an array of strings - what you passed didn't work for me at all - #{args[0].class}")
+ end
+ end
+end
diff --git a/lib/puppet/provider/file_line/ruby.rb b/lib/puppet/provider/file_line/ruby.rb
index 63bbd8e..f5d3a32 100644
--- a/lib/puppet/provider/file_line/ruby.rb
+++ b/lib/puppet/provider/file_line/ruby.rb
@@ -1,7 +1,7 @@
Puppet::Type.type(:file_line).provide(:ruby) do
def exists?
- File.readlines(resource[:path]).find do |line|
+ lines.find do |line|
line.chomp == resource[:line].chomp
end
end
@@ -12,4 +12,16 @@ Puppet::Type.type(:file_line).provide(:ruby) do
end
end
+ def destroy
+ local_lines = lines
+ File.open(resource[:path],'w') do |fh|
+ fh.write(local_lines.reject{|l| l.chomp == resource[:line] }.join(''))
+ end
+ end
+
+ private
+ def lines
+ @lines ||= File.readlines(resource[:path])
+ end
+
end
diff --git a/lib/puppet/type/file_line.rb b/lib/puppet/type/file_line.rb
index 8b45897..9f03771 100644
--- a/lib/puppet/type/file_line.rb
+++ b/lib/puppet/type/file_line.rb
@@ -23,12 +23,7 @@ Puppet::Type.newtype(:file_line) do
EOT
- ensurable do
- defaultto :present
- newvalue(:present) do
- provider.create
- end
- end
+ ensurable
newparam(:name, :namevar => true) do
desc 'arbitrary name used as identity'
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index d6837a9..e29c315 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -1,8 +1,6 @@
dir = File.expand_path(File.dirname(__FILE__))
$LOAD_PATH.unshift File.join(dir, 'lib')
-p dir
-
# Don't want puppet getting the command line arguments for rake or autotest
ARGV.clear
diff --git a/spec/unit/facter/root_home_spec.rb b/spec/unit/facter/root_home_spec.rb
index 8946d9d..ce80684 100644
--- a/spec/unit/facter/root_home_spec.rb
+++ b/spec/unit/facter/root_home_spec.rb
@@ -30,13 +30,11 @@ describe Facter::Util::RootHome do
end
end
context "windows" do
- let(:root_ent) { "FIXME TBD on Windows" }
- let(:expected_root_home) { "FIXME TBD on Windows" }
-
- it "should return FIXME TBD on windows" do
- pending "FIXME: TBD on windows"
- Facter::Util::Resolution.expects(:exec).with("getent passwd root").returns(root_ent)
- Facter::Util::RootHome.get_root_home.should == expected_root_home
+ before :each do
+ Facter::Util::Resolution.expects(:exec).with("getent passwd root").returns(nil)
+ end
+ it "should be nil on windows" do
+ Facter::Util::RootHome.get_root_home.should be_nil
end
end
end
diff --git a/spec/unit/facter/util/puppet_settings_spec.rb b/spec/unit/facter/util/puppet_settings_spec.rb
new file mode 100644
index 0000000..c3ce6ea
--- /dev/null
+++ b/spec/unit/facter/util/puppet_settings_spec.rb
@@ -0,0 +1,35 @@
+require 'spec_helper'
+require 'facter/util/puppet_settings'
+
+describe Facter::Util::PuppetSettings do
+
+ describe "#with_puppet" do
+ context "Without Puppet loaded" do
+ before(:each) do
+ Module.expects(:const_get).with("Puppet").raises(NameError)
+ end
+
+ it 'should be nil' do
+ subject.with_puppet { Puppet[:vardir] }.should be_nil
+ end
+ it 'should not yield to the block' do
+ Puppet.expects(:[]).never
+ subject.with_puppet { Puppet[:vardir] }.should be_nil
+ end
+ end
+ context "With Puppet loaded" do
+ module Puppet; end
+ let(:vardir) { "/var/lib/puppet" }
+
+ before :each do
+ Puppet.expects(:[]).with(:vardir).returns vardir
+ end
+ it 'should yield to the block' do
+ subject.with_puppet { Puppet[:vardir] }
+ end
+ it 'should return the nodes vardir' do
+ subject.with_puppet { Puppet[:vardir] }.should eq vardir
+ end
+ end
+ end
+end
diff --git a/spec/unit/puppet/parser/functions/get_module_path_spec.rb b/spec/unit/puppet/parser/functions/get_module_path_spec.rb
new file mode 100644
index 0000000..d8340f4
--- /dev/null
+++ b/spec/unit/puppet/parser/functions/get_module_path_spec.rb
@@ -0,0 +1,42 @@
+#!/usr/bin/env rspec
+require 'puppet'
+require 'fileutils'
+require 'spec_helper'
+describe Puppet::Parser::Functions.function(:get_module_path) do
+ include PuppetSpec::Files
+
+ def get_scope(environment = 'production')
+ scope = Puppet::Parser::Scope.new
+ scope.compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("floppy", :environment => environment))
+ scope
+ end
+ it 'should only allow one argument' do
+ expect { get_scope.function_get_module_path([]) }.should raise_error(Puppet::ParseError, /Wrong number of arguments, expects one/)
+ expect { get_scope.function_get_module_path(['1','2','3']) }.should raise_error(Puppet::ParseError, /Wrong number of arguments, expects one/)
+ end
+ it 'should raise an exception when the module cannot be found' do
+ expect { get_scope.function_get_module_path(['foo']) }.should raise_error(Puppet::ParseError, /Could not find module/)
+ end
+ describe 'when locating a module' do
+ let(:modulepath) { tmpdir('modulepath') }
+ let(:foo_path) { File.join(modulepath, 'foo') }
+ before(:each) { FileUtils.mkdir(foo_path) }
+ it 'should be able to find module paths from the modulepath setting' do
+ Puppet[:modulepath] = modulepath
+ get_scope.function_get_module_path(['foo']).should == foo_path
+ end
+ it 'should be able to find module paths when the modulepath is a list' do
+ Puppet[:modulepath] = modulepath + ":/tmp"
+ get_scope.function_get_module_path(['foo']).should == foo_path
+ end
+ it 'should be able to find module paths from the environment' do
+ conf_file = tmpfile('conffile')
+ File.open(conf_file, 'w') do |fh|
+ fh.write("[dansenvironment]\nmodulepath = #{modulepath}")
+ end
+ Puppet[:config] = conf_file
+ Puppet.parse_config
+ get_scope('dansenvironment').function_get_module_path(['foo']).should ==foo_path
+ end
+ end
+end
diff --git a/spec/unit/puppet/parser/functions/str2saltedsha512_spec.rb b/spec/unit/puppet/parser/functions/str2saltedsha512_spec.rb
new file mode 100644
index 0000000..11485aa
--- /dev/null
+++ b/spec/unit/puppet/parser/functions/str2saltedsha512_spec.rb
@@ -0,0 +1,51 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the str2saltedsha512 function" do
+ before :all do
+ Puppet::Parser::Functions.autoloader.loadall
+ end
+
+ before :each do
+ @scope = Puppet::Parser::Scope.new
+ end
+
+ it "should exist" do
+ Puppet::Parser::Functions.function("str2saltedsha512").should == "function_str2saltedsha512"
+ end
+
+ it "should raise a ParseError if there is less than 1 argument" do
+ expect { @scope.function_str2saltedsha512([]) }.should( raise_error(Puppet::ParseError) )
+ end
+
+ it "should raise a ParseError if there is more than 1 argument" do
+ expect { @scope.function_str2saltedsha512(['foo', 'bar', 'baz']) }.should( raise_error(Puppet::ParseError) )
+ end
+
+ it "should return a salted-sha512 password hash 136 characters in length" do
+ result = @scope.function_str2saltedsha512(["password"])
+ result.length.should(eq(136))
+ end
+
+ it "should raise an error if you pass a non-string password" do
+ expect { @scope.function_str2saltedsha512([1234]) }.should( raise_error(Puppet::ParseError) )
+ end
+
+ it "should generate a valid password" do
+ # Allow the function to generate a password based on the string 'password'
+ password_hash = @scope.function_str2saltedsha512(["password"])
+
+ # Separate the Salt and Password from the Password Hash
+ salt = password_hash[0..7]
+ password = password_hash[8..-1]
+
+ # Convert the Salt and Password from Hex to Binary Data
+ str_salt = Array(salt.lines).pack('H*')
+ str_password = Array(password.lines).pack('H*')
+
+ # Combine the Binary Salt with 'password' and compare the end result
+ saltedpass = Digest::SHA512.digest(str_salt + 'password')
+ result = (str_salt + saltedpass).unpack('H*')[0]
+ result.should == password_hash
+ end
+end
diff --git a/spec/unit/puppet/parser/functions/validate_absolute_path_spec.rb b/spec/unit/puppet/parser/functions/validate_absolute_path_spec.rb
new file mode 100644
index 0000000..1e0b5ac
--- /dev/null
+++ b/spec/unit/puppet/parser/functions/validate_absolute_path_spec.rb
@@ -0,0 +1,83 @@
+require 'spec_helper'
+
+describe Puppet::Parser::Functions.function(:validate_absolute_path) do
+ before :all do
+ Puppet::Parser::Functions.autoloader.loadall
+ end
+
+ # The subject of these examplres is the method itself.
+ subject do
+ Puppet::Parser::Scope.new.method :function_validate_absolute_path
+ end
+
+ describe "Valid Paths" do
+ def self.valid_paths
+ %w{
+ C:/
+ C:\\
+ C:\\WINDOWS\\System32
+ C:/windows/system32
+ X:/foo/bar
+ X:\\foo\\bar
+ /var/tmp
+ /var/lib/puppet
+ /var/opt/../lib/puppet
+ }
+ end
+
+ context "Without Puppet::Util.absolute_path? (e.g. Puppet <= 2.6)" do
+ before :each do
+ # The intent here is to mock Puppet to behave like Puppet 2.6 does.
+ # Puppet 2.6 does not have the absolute_path? method. This is only a
+ # convenience test, stdlib should be run with the Puppet 2.6.x in the
+ # $LOAD_PATH in addition to 2.7.x and master.
+ Puppet::Util.expects(:respond_to?).with(:absolute_path?).returns(false)
+ end
+ valid_paths.each do |path|
+ it "validate_absolute_path(#{path.inspect}) should not fail" do
+ expect { subject.call [path] }.not_to raise_error Puppet::ParseError
+ end
+ end
+ end
+
+ context "Puppet without mocking" do
+ valid_paths.each do |path|
+ it "validate_absolute_path(#{path.inspect}) should not fail" do
+ expect { subject.call [path] }.not_to raise_error Puppet::ParseError
+ end
+ end
+ end
+ end
+
+ describe 'Invalid paths' do
+ context 'Garbage inputs' do
+ [
+ nil,
+ [ nil ],
+ { 'foo' => 'bar' },
+ { },
+ '',
+ ].each do |path|
+ it "validate_absolute_path(#{path.inspect}) should fail" do
+ expect { subject.call [path] }.to raise_error Puppet::ParseError
+ end
+ end
+ end
+
+ context 'Relative paths' do
+ %w{
+ relative1
+ .
+ ..
+ ./foo
+ ../foo
+ etc/puppetlabs/puppet
+ opt/puppet/bin
+ }.each do |path|
+ it "validate_absolute_path(#{path.inspect}) should fail" do
+ expect { subject.call [path] }.to raise_error Puppet::ParseError
+ end
+ end
+ end
+ end
+end
diff --git a/spec/unit/puppet/parser/functions/validate_re_spec.rb b/spec/unit/puppet/parser/functions/validate_re_spec.rb
new file mode 100644
index 0000000..c35ae14
--- /dev/null
+++ b/spec/unit/puppet/parser/functions/validate_re_spec.rb
@@ -0,0 +1,80 @@
+require 'spec_helper'
+
+describe Puppet::Parser::Functions.function(:validate_re) do
+ before :all do
+ Puppet::Parser::Functions.autoloader.loadall
+ end
+
+ let(:scope) do
+ scope = Puppet::Parser::Scope.new
+ end
+
+ # The subject of these examplres is the method itself.
+ subject do
+ scope.method :function_validate_re
+ end
+
+ context 'Using Puppet::Parser::Scope.new' do
+
+ describe 'Garbage inputs' do
+ inputs = [
+ [ nil ],
+ [ [ nil ] ],
+ [ { 'foo' => 'bar' } ],
+ [ { } ],
+ [ '' ],
+ [ "one", "one", "MSG to User", "4th arg" ],
+ ]
+
+ inputs.each do |input|
+ it "validate_re(#{input.inspect}) should fail" do
+ expect { subject.call [input] }.to raise_error Puppet::ParseError
+ end
+ end
+ end
+
+ describe 'Valid inputs' do
+ inputs = [
+ [ '/full/path/to/something', '^/full' ],
+ [ '/full/path/to/something', 'full' ],
+ [ '/full/path/to/something', ['full', 'absent'] ],
+ [ '/full/path/to/something', ['full', 'absent'], 'Message to the user' ],
+ ]
+
+ inputs.each do |input|
+ it "validate_re(#{input.inspect}) should not fail" do
+ expect { subject.call input }.not_to raise_error
+ end
+ end
+ end
+ describe "Valid inputs which should raise an exception without a message" do
+ # The intent here is to make sure valid inputs raise exceptions when they
+ # don't specify an error message to display. This is the behvior in
+ # 2.2.x and prior.
+ inputs = [
+ [ "hello", [ "bye", "later", "adios" ] ],
+ [ "greetings", "salutations" ],
+ ]
+
+ inputs.each do |input|
+ it "validate_re(#{input.inspect}) should fail" do
+ expect { subject.call input }.to raise_error /validate_re.*?does not match/
+ end
+ end
+ end
+ describe "Nicer Error Messages" do
+ # The intent here is to make sure the function returns the 3rd argument
+ # in the exception thrown
+ inputs = [
+ [ "hello", [ "bye", "later", "adios" ], "MSG to User" ],
+ [ "greetings", "salutations", "Error, greetings does not match salutations" ],
+ ]
+
+ inputs.each do |input|
+ it "validate_re(#{input.inspect}) should fail" do
+ expect { subject.call input }.to raise_error /#{input[2]}/
+ end
+ end
+ end
+ end
+end
diff --git a/spec/unit/puppet/parser/functions/validate_slength_spec.rb b/spec/unit/puppet/parser/functions/validate_slength_spec.rb
new file mode 100755
index 0000000..d2d4ca0
--- /dev/null
+++ b/spec/unit/puppet/parser/functions/validate_slength_spec.rb
@@ -0,0 +1,52 @@
+#!/usr/bin/env rspec
+
+require 'spec_helper'
+
+describe "the validate_slength function" do
+ before :all do
+ Puppet::Parser::Functions.autoloader.loadall
+ end
+
+ let(:scope) { Puppet::Parser::Scope.new }
+
+ it "should exist" do
+ Puppet::Parser::Functions.function("validate_slength").should == "function_validate_slength"
+ end
+
+ it "should raise a ParseError if there is less than 2 arguments" do
+ expect { scope.function_validate_slength([]) }.to(raise_error(Puppet::ParseError))
+ expect { scope.function_validate_slength(["asdf"]) }.to(raise_error(Puppet::ParseError))
+ end
+
+ it "should raise a ParseError if argument 2 doesn't convert to a fixnum" do
+ expect { scope.function_validate_slength(["moo",["2"]]) }.to(raise_error(Puppet::ParseError, /Couldn't convert whatever you passed/))
+ end
+
+ it "should raise a ParseError if argument 2 converted, but to 0, e.g. a string" do
+ expect { scope.function_validate_slength(["moo","monkey"]) }.to(raise_error(Puppet::ParseError, /please pass a positive number as max_length/))
+ end
+
+ it "should raise a ParseError if argument 2 converted, but to 0" do
+ expect { scope.function_validate_slength(["moo","0"]) }.to(raise_error(Puppet::ParseError, /please pass a positive number as max_length/))
+ end
+
+ it "should fail if string greater then size" do
+ expect { scope.function_validate_slength(["test", 2]) }.to(raise_error(Puppet::ParseError, /It should have been less than or equal to/))
+ end
+
+ it "should fail if you pass an array of something other than strings" do
+ expect { scope.function_validate_slength([["moo",["moo"],Hash.new["moo" => 7]], 7]) }.to(raise_error(Puppet::ParseError, /is not a string, it's a/))
+ end
+
+ it "should fail if you pass something other than a string or array" do
+ expect { scope.function_validate_slength([Hash.new["moo" => "7"],6]) }.to(raise_error(Puppet::ParseError), /please pass a string, or an array of strings/)
+ end
+
+ it "should not fail if string is smaller or equal to size" do
+ expect { scope.function_validate_slength(["test", 5]) }.to_not(raise_error(Puppet::ParseError))
+ end
+
+ it "should not fail if array of string is are all smaller or equal to size" do
+ expect { scope.function_validate_slength([["moo","foo","bar"], 5]) }.to_not(raise_error(Puppet::ParseError))
+ end
+end
diff --git a/spec/unit/puppet/provider/file_line/ruby_spec.rb b/spec/unit/puppet/provider/file_line/ruby_spec.rb
index b03fc0e..b62e3a8 100644
--- a/spec/unit/puppet/provider/file_line/ruby_spec.rb
+++ b/spec/unit/puppet/provider/file_line/ruby_spec.rb
@@ -2,29 +2,66 @@ require 'puppet'
require 'tempfile'
provider_class = Puppet::Type.type(:file_line).provider(:ruby)
describe provider_class do
- before :each do
- tmp = Tempfile.new('tmp')
- @tmpfile = tmp.path
- tmp.close!
- @resource = Puppet::Type::File_line.new(
- {:name => 'foo', :path => @tmpfile, :line => 'foo'}
- )
- @provider = provider_class.new(@resource)
- end
- it 'should detect if the line exists in the file' do
- File.open(@tmpfile, 'w') do |fh|
- fh.write('foo')
+ context "add" do
+ before :each do
+ tmp = Tempfile.new('tmp')
+ @tmpfile = tmp.path
+ tmp.close!
+ @resource = Puppet::Type::File_line.new(
+ {:name => 'foo', :path => @tmpfile, :line => 'foo'}
+ )
+ @provider = provider_class.new(@resource)
end
- @provider.exists?.should be_true
- end
- it 'should detect if the line does not exist in the file' do
- File.open(@tmpfile, 'w') do |fh|
- fh.write('foo1')
+ it 'should detect if the line exists in the file' do
+ File.open(@tmpfile, 'w') do |fh|
+ fh.write('foo')
+ end
+ @provider.exists?.should be_true
+ end
+ it 'should detect if the line does not exist in the file' do
+ File.open(@tmpfile, 'w') do |fh|
+ fh.write('foo1')
+ end
+ @provider.exists?.should be_nil
+ end
+ it 'should append to an existing file when creating' do
+ @provider.create
+ File.read(@tmpfile).chomp.should == 'foo'
end
- @provider.exists?.should be_nil
end
- it 'should append to an existing file when creating' do
- @provider.create
- File.read(@tmpfile).chomp.should == 'foo'
+
+ context "remove" do
+ before :each do
+ tmp = Tempfile.new('tmp')
+ @tmpfile = tmp.path
+ tmp.close!
+ @resource = Puppet::Type::File_line.new(
+ {:name => 'foo', :path => @tmpfile, :line => 'foo', :ensure => 'absent' }
+ )
+ @provider = provider_class.new(@resource)
+ end
+ it 'should remove the line if it exists' do
+ File.open(@tmpfile, 'w') do |fh|
+ fh.write("foo1\nfoo\nfoo2")
+ end
+ @provider.destroy
+ File.read(@tmpfile).should eql("foo1\nfoo2")
+ end
+
+ it 'should remove the line without touching the last new line' do
+ File.open(@tmpfile, 'w') do |fh|
+ fh.write("foo1\nfoo\nfoo2\n")
+ end
+ @provider.destroy
+ File.read(@tmpfile).should eql("foo1\nfoo2\n")
+ end
+
+ it 'should remove any occurence of the line' do
+ File.open(@tmpfile, 'w') do |fh|
+ fh.write("foo1\nfoo\nfoo2\nfoo\nfoo")
+ end
+ @provider.destroy
+ File.read(@tmpfile).should eql("foo1\nfoo2\n")
+ end
end
end