summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md4
-rw-r--r--Gemfile8
-rw-r--r--README.markdown205
-rw-r--r--lib/facter/package_provider.rb21
-rw-r--r--lib/facter/pe_version.rb9
-rw-r--r--lib/facter/root_home.rb2
-rw-r--r--lib/facter/service_provider.rb17
-rw-r--r--lib/puppet/functions/is_a.rb32
-rw-r--r--lib/puppet/parser/functions/bool2str.rb26
-rw-r--r--lib/puppet/parser/functions/empty.rb12
-rw-r--r--lib/puppet/parser/functions/intersection.rb6
-rw-r--r--lib/puppet/parser/functions/load_module_metadata.rb16
-rw-r--r--lib/puppet/parser/functions/parsejson.rb25
-rw-r--r--lib/puppet/parser/functions/parseyaml.rb22
-rw-r--r--lib/puppet/parser/functions/str2bool.rb8
-rw-r--r--lib/puppet/parser/functions/validate_ip_address.rb50
-rw-r--r--lib/puppet/parser/functions/validate_ipv4_address.rb2
-rw-r--r--lib/puppet/parser/functions/validate_re.rb11
-rw-r--r--lib/puppet/type/file_line.rb11
-rw-r--r--manifests/stages.pp2
-rwxr-xr-xspec/acceptance/empty_spec.rb14
-rw-r--r--spec/acceptance/is_a_spec.rb30
-rwxr-xr-xspec/acceptance/parsejson_spec.rb23
-rwxr-xr-xspec/acceptance/parseyaml_spec.rb25
-rwxr-xr-xspec/functions/bool2str_spec.rb6
-rwxr-xr-xspec/functions/empty_spec.rb2
-rw-r--r--spec/functions/is_a_spec.rb25
-rwxr-xr-xspec/functions/load_module_metadata.rb16
-rwxr-xr-xspec/functions/load_module_metadata_spec.rb29
-rwxr-xr-xspec/functions/parsejson_spec.rb65
-rwxr-xr-xspec/functions/parseyaml_spec.rb83
-rwxr-xr-xspec/functions/str2bool_spec.rb4
-rw-r--r--spec/functions/type_of_spec.rb4
-rw-r--r--spec/functions/validate_ip_address_spec.rb46
-rwxr-xr-xspec/functions/validate_re_spec.rb15
-rwxr-xr-xspec/spec_helper_acceptance.rb6
-rw-r--r--spec/unit/facter/package_provider_spec.rb37
-rwxr-xr-xspec/unit/facter/pe_version_spec.rb12
-rwxr-xr-xspec/unit/facter/root_home_spec.rb2
-rw-r--r--spec/unit/facter/service_provider_spec.rb37
40 files changed, 851 insertions, 119 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2e2fffe..83f57f5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -361,7 +361,7 @@ This is a supported release
* Add an ensure\_packages function. (8a8c09e)
-##### 2012-11-23 - Erik Dalén <dalen@spotify.com> - 3.2.0
+##### 2012-11-23 - Erik Dalén <dalen@spotify.com> - 3.2.0
* (#17797) min() and max() functions (9954133)
@@ -458,7 +458,7 @@ This is a supported release
* Add support for a 'match' parameter to file\_line (a06c0d8)
-##### 2012-08-07 - Erik Dalén <dalen@spotify.com> - 2.4.0
+##### 2012-08-07 - Erik Dalén <dalen@spotify.com> - 2.4.0
* (#15872) Add to\_bytes function (247b69c)
diff --git a/Gemfile b/Gemfile
index fbb9a25..8221514 100644
--- a/Gemfile
+++ b/Gemfile
@@ -11,8 +11,14 @@ def location_for(place, fake_version = nil)
end
group :development, :unit_tests do
+ # rspec must be v2 for ruby 1.8.7
+ if RUBY_VERSION >= '1.8.7' and RUBY_VERSION < '1.9'
+ gem 'rspec', '~> 2.0'
+ else
+ gem 'rspec', '~> 3.1.0', :require => false
+ end
+
gem 'rake', '~> 10.1.0', :require => false
- gem 'rspec', '~> 3.1.0', :require => false
gem 'rspec-puppet', '~> 2.2', :require => false
gem 'mocha', :require => false
# keep for its rake task for now
diff --git a/README.markdown b/README.markdown
index a880222..526b573 100644
--- a/README.markdown
+++ b/README.markdown
@@ -76,18 +76,56 @@ The `stdlib::stages` class declares various run stages for deploying infrastruct
### Types
#### `file_line`
- Ensures that a given line, including whitespace at the beginning and end, is contained within a file. If the line is not contained in the given file, Puppet will add the line. Multiple resources can be declared to manage multiple lines in the same file. You can also use `match` to replace existing lines.
- ~~~
- file_line { 'sudo_rule':
- path => '/etc/sudoers',
- line => '%sudo ALL=(ALL) ALL',
- }
- file_line { 'sudo_rule_nopw':
- path => '/etc/sudoers',
- line => '%sudonopw ALL=(ALL) NOPASSWD: ALL',
- }
- ~~~
+Ensures that a given line is contained within a file. The implementation
+matches the full line, including whitespace at the beginning and end. If
+the line is not contained in the given file, Puppet will append the line to
+the end of the file to ensure the desired state. Multiple resources may
+be declared to manage multiple lines in the same file.
+
+Example:
+
+ file_line { 'sudo_rule':
+ path => '/etc/sudoers',
+ line => '%sudo ALL=(ALL) ALL',
+ }
+
+ file_line { 'sudo_rule_nopw':
+ path => '/etc/sudoers',
+ line => '%sudonopw ALL=(ALL) NOPASSWD: ALL',
+ }
+
+In this example, Puppet will ensure both of the specified lines are
+contained in the file /etc/sudoers.
+
+Match Example:
+
+ file_line { 'bashrc_proxy':
+ ensure => present,
+ path => '/etc/bashrc',
+ line => 'export HTTP_PROXY=http://squid.puppetlabs.vm:3128',
+ match => '^export\ HTTP_PROXY\=',
+ }
+
+In this code example match will look for a line beginning with export
+followed by HTTP_PROXY and replace it with the value in line.
+
+Match Example With `ensure => absent`:
+
+ file_line { 'bashrc_proxy':
+ ensure => absent,
+ path => '/etc/bashrc',
+ line => 'export HTTP_PROXY=http://squid.puppetlabs.vm:3128',
+ match => '^export\ HTTP_PROXY\=',
+ match_for_absence => true,
+ }
+
+In this code example match will look for a line beginning with export
+followed by HTTP_PROXY and delete it. If multiple lines match, an
+error will be raised unless the `multiple => true` parameter is set.
+
+**Autorequires:** If Puppet is managing the file that will contain the line
+being managed, the file_line resource will autorequire that file.
##### Parameters
All parameters are optional, unless otherwise noted.
@@ -95,13 +133,13 @@ All parameters are optional, unless otherwise noted.
* `after`: Specifies the line after which Puppet will add any new lines. (Existing lines are added in place.) Valid options: String. Default: Undefined.
* `ensure`: Ensures whether the resource is present. Valid options: 'present', 'absent'. Default: 'present'.
* `line`: **Required.** Sets the line to be added to the file located by the `path` parameter. Valid options: String. Default: Undefined.
-* `match`: Specifies a regular expression to run against existing lines in the file; if a match is found, it is replaced rather than adding a new line. Valid options: String containing a regex. Default: Undefined.
+* `match`: Specifies a regular expression to run against existing lines in the file; if a match is found, it is replaced rather than adding a new line. A regex comparison is performed against the line value and if it does not match an exception will be raised. Valid options: String containing a regex. Default: Undefined.
+* `match_for_absence`: An optional value to determine if match should be applied when `ensure => absent`. If set to true and match is set, the line that matches match will be deleted. If set to false (the default), match is ignored when `ensure => absent` and the value of `line` is used instead. Default: false.
* `multiple`: Determines if `match` and/or `after` can change multiple lines. If set to false, an exception will be raised if more than one line matches. Valid options: 'true', 'false'. Default: Undefined.
* `name`: Sets the name to use as the identity of the resource. This is necessary if you want the resource namevar to differ from the supplied `title` of the resource. Valid options: String. Default: Undefined.
* `path`: **Required.** Defines the file in which Puppet will ensure the line specified by `line`. Must be an absolute path to the file.
* `replace`: Defines whether the resource will overwrite an existing line that matches the `match` parameter. If set to false and a line is found matching the `match` param, the line will not be placed in the file. Valid options: true, false, yes, no. Default: true
-
### Functions
#### `abs`
@@ -132,9 +170,25 @@ Converts a boolean to a number. Converts values:
* 'true', 't', '1', 'y', and 'yes' to 1.
Requires a single boolean or string as an input. *Type*: rvalue.
+#### `bool2str`
+
+Converts a boolean to a string using optionally supplied arguments. The optional
+second and third arguments represent what true and false will be converted to
+respectively. If only one argument is given, it will be converted from a boolean
+to a string containing 'true' or 'false'.
+
+*Examples:*
+~~~
+bool2str(true) => 'true'
+bool2str(true, 'yes', 'no') => 'yes'
+bool2str(false, 't', 'f') => 'f'
+~~~
+
+Requires a single boolean as input. *Type*: rvalue.
+
#### `capitalize`
-Capitalizes the first letter of a string or array of strings. Requires either a single string or an array as an input. *Type*: rvalue.
+Capitalizes the first character of a string or array of strings, and lower-cases the remaining characters of each string. Requires either a single string or an array as an input. *Type*: rvalue.
#### `ceiling`
@@ -224,7 +278,7 @@ Converts the case of a string or of all strings in an array to lowercase. *Type*
#### `empty`
-Returns 'true' if the variable is empty. *Type*: rvalue.
+Returns true if the argument is an array or hash that contains no elements, or an empty string. Returns false when the argument is a numerical value. *Type*: rvalue.
#### `ensure_packages`
@@ -403,6 +457,29 @@ Converts an array into a hash. For example, `hash(['a',1,'b',2,'c',3])` returns
Returns an array an intersection of two. For example, `intersection(["a","b","c"],["b","c","d"])` returns ["b","c"]. *Type*: rvalue.
+#### `is_a`
+
+Boolean check to determine whether a variable is of a given data type. This is equivalent to the `=~` type checks. This function is only available in Puppet 4, or when using the "future" parser.
+
+ ~~~
+ foo = 3
+ $bar = [1,2,3]
+ $baz = 'A string!'
+
+ if $foo.is_a(Integer) {
+ notify { 'foo!': }
+ }
+ if $bar.is_a(Array) {
+ notify { 'bar!': }
+ }
+ if $baz.is_a(String) {
+ notify { 'baz!': }
+ }
+ ~~~
+
+See the documentation for "The Puppet Type System" for more information about types.
+See the `assert_type()` function for flexible ways to assert the type of a value.
+
#### `is_array`
Returns 'true' if the variable passed to this function is an array. *Type*: rvalue.
@@ -478,6 +555,15 @@ Loads the metadata.json of a target module. Can be used to determine module vers
notify { $metadata['author']: }
~~~
+If you do not want to fail the catalog compilation if the metadata file for a module is not present:
+
+ ~~~
+ $metadata = load_module_metadata('mysql', true)
+ if empty($metadata) {
+ notify { "This module does not have a metadata.json file.": }
+ }
+ ~~~
+
*Type*: rvalue.
#### `lstrip`
@@ -521,10 +607,12 @@ Converts a number or a string representation of a number into a true boolean. Ze
#### `parsejson`
Converts a string of JSON into the correct Puppet structure. *Type*: rvalue.
+The optional second argument will be returned if the data was not correct.
#### `parseyaml`
Converts a string of YAML into the correct Puppet structure. *Type*: rvalue.
+The optional second argument will be returned if the data was not correct.
#### `pick`
@@ -536,6 +624,10 @@ From a list of values, returns the first value that is not undefined or an empty
*Type*: rvalue.
+#### `pick_default`
+
+Will return the first value in a list of values. Contrary to the 'pick()' function, the 'pick_default()' does not fail if all arguments are empty. This allows it to use an empty value as default. *Type*: rvalue.
+
#### `prefix`
Applies a prefix to all elements in an array, or to the keys in a hash.
@@ -623,7 +715,7 @@ Returns a new string where runs of the same character that occur in this set are
#### `str2bool`
-Converts a string to a boolean. This attempts to convert strings that contain values such as '1', 't', 'y', and 'yes' to 'true' and strings that contain values such as '0', 'f', 'n', and 'no' to 'false'. *Type*: rvalue.
+Converts certain strings to a boolean. This attempts to convert strings that contain the values '1', 't', 'y', and 'yes' to 'true'. Strings that contain values '0', 'f', 'n', and 'no', or are an an empty string or undefined are converted to 'false'. Any other value will cause an error. *Type*: rvalue.
#### `str2saltedsha512`
@@ -706,12 +798,18 @@ Converts the argument into bytes, for example "4 kB" becomes "4096". Takes a sin
*Type*: rvalue.
-Looks up into a complex structure of arrays and hashes and returns a value
-or the default value if nothing was found.
+Looks up into a complex structure of arrays and hashes to extract a value by
+its path in the structure. The path is a string of hash keys or array indexes
+starting with zero, separated by the path separator character (default "/").
+The function will go down the structure by each path component and will try to
+return the value at the end of the path.
-Key can contain slashes to describe path components. The function will go down
-the structure and try to extract the required value.
+In addition to the required "path" argument the function accepts the default
+argument. It will be returned if the path is not correct, no value was found or
+a any other error have occurred. And the last argument can set the path
+separator character.
+```ruby
$data = {
'a' => {
'b' => [
@@ -722,19 +820,28 @@ $data = {
}
}
+$value = try_get_value($data, 'a/b/2')
+# $value = 'b3'
+
+# with all possible options
$value = try_get_value($data, 'a/b/2', 'not_found', '/')
-=> $value = 'b3'
+# $value = 'b3'
-a -> first hash key
-b -> second hash key
-2 -> array index starting with 0
+# using the default value
+$value = try_get_value($data, 'a/b/c/d', 'not_found')
+# $value = 'not_found'
-not_found -> (optional) will be returned if there is no value or the path did not match. Defaults to nil.
-/ -> (optional) path delimiter. Defaults to '/'.
+# using custom separator
+$value = try_get_value($data, 'a|b', [], '|')
+# $value = ['b1','b2','b3']
+```
-In addition to the required "key" argument, "try_get_value" accepts default
-argument. It will be returned if no value was found or a path component is
-missing. And the fourth argument can set a variable path separator.
+1. **$data** The data structure we are working with.
+2. **'a/b/2'** The path string.
+3. **'not_found'** The default value. It will be returned if nothing is found.
+ (optional, defaults to *undef*)
+4. **'/'** The path separator character.
+ (optional, defaults to *'/'*)
#### `type3x`
@@ -972,6 +1079,39 @@ Validates that the first argument is an integer (or an array of integers). Abort
*Type*: statement.
+#### `validate_ip_address`
+
+Validates that argument is an IP address, regardless of it is an IPv4 or an IPv6
+address. It validates as well IP address with netmask. It must be an String, as
+well.
+
+The following values will pass:
+
+ ~~~
+ validate_ip_address('0.0.0.0')
+ validate_ip_address('8.8.8.8')
+ validate_ip_address('127.0.0.1')
+ validate_ip_address('194.232.104.150')
+ validate_ip_address('3ffe:0505:0002::')
+ validate_ip_address('::1/64')
+ validate_ip_address('fe80::a00:27ff:fe94:44d6/64')
+ validate_ip_address('8.8.8.8/32')
+ ~~~
+
+The following values will fail, causing compilation to abort:
+
+ ~~~
+ validate_ip_address(1)
+ validate_ip_address(true)
+ validate_ip_address(0.0.0.256)
+ validate_ip_address('::1', {})
+ validate_ip_address('0.0.0.0.0')
+ validate_ip_address('3.3.3')
+ validate_ip_address('23.43.9.22/64')
+ validate_ip_address('260.2.32.43')
+ ~~~
+
+
#### `validate_numeric`
Validates that the first argument is a numeric value (or an array of numeric values). Aborts catalog compilation if any of the checks fail.
@@ -1014,6 +1154,13 @@ test, and the second argument should be a stringified regular expression (withou
validate_re($::puppetversion, '^2.7', 'The $puppetversion fact value does not match 2.7')
~~~
+ Note: Compilation will also abort, if the first argument is not a String. Always use
+ quotes to force stringification:
+
+ ~~~
+ validate_re("${::operatingsystemmajrelease}", '^[57]$')
+ ~~~
+
*Type*: statement.
#### `validate_slength`
diff --git a/lib/facter/package_provider.rb b/lib/facter/package_provider.rb
new file mode 100644
index 0000000..65a2da0
--- /dev/null
+++ b/lib/facter/package_provider.rb
@@ -0,0 +1,21 @@
+# Fact: package_provider
+#
+# Purpose: Returns the default provider Puppet will choose to manage packages
+# on this system
+#
+# Resolution: Instantiates a dummy package resource and return the provider
+#
+# Caveats:
+#
+require 'puppet/type'
+require 'puppet/type/package'
+
+Facter.add(:package_provider) do
+ setcode do
+ if Gem::Version.new(Facter.value(:puppetversion)) >= Gem::Version.new('3.6')
+ Puppet::Type.type(:package).newpackage(:name => 'dummy', :allow_virtual => 'true')[:provider].to_s
+ else
+ Puppet::Type.type(:package).newpackage(:name => 'dummy')[:provider].to_s
+ end
+ end
+end
diff --git a/lib/facter/pe_version.rb b/lib/facter/pe_version.rb
index 0cc0f64..c9f2181 100644
--- a/lib/facter/pe_version.rb
+++ b/lib/facter/pe_version.rb
@@ -10,8 +10,13 @@
#
Facter.add("pe_version") do
setcode do
- pe_ver = Facter.value("puppetversion").match(/Puppet Enterprise (\d+\.\d+\.\d+)/)
- pe_ver[1] if pe_ver
+ puppet_ver = Facter.value("puppetversion")
+ if puppet_ver != nil
+ pe_ver = puppet_ver.match(/Puppet Enterprise (\d+\.\d+\.\d+)/)
+ pe_ver[1] if pe_ver
+ else
+ nil
+ end
end
end
diff --git a/lib/facter/root_home.rb b/lib/facter/root_home.rb
index ee3ffa8..87c7657 100644
--- a/lib/facter/root_home.rb
+++ b/lib/facter/root_home.rb
@@ -35,7 +35,7 @@ Facter.add(:root_home) do
confine :kernel => :aix
root_home = nil
setcode do
- str = Facter::Util::Resolution.exec("lsuser -C -a home root")
+ str = Facter::Util::Resolution.exec("lsuser -c -a home root")
str && str.split("\n").each do |line|
next if line =~ /^#/
root_home = line.split(/:/)[1]
diff --git a/lib/facter/service_provider.rb b/lib/facter/service_provider.rb
new file mode 100644
index 0000000..a117921
--- /dev/null
+++ b/lib/facter/service_provider.rb
@@ -0,0 +1,17 @@
+# Fact: service_provider
+#
+# Purpose: Returns the default provider Puppet will choose to manage services
+# on this system
+#
+# Resolution: Instantiates a dummy service resource and return the provider
+#
+# Caveats:
+#
+require 'puppet/type'
+require 'puppet/type/service'
+
+Facter.add(:service_provider) do
+ setcode do
+ Puppet::Type.type(:service).newservice(:name => 'dummy')[:provider].to_s
+ end
+end
diff --git a/lib/puppet/functions/is_a.rb b/lib/puppet/functions/is_a.rb
new file mode 100644
index 0000000..da98b03
--- /dev/null
+++ b/lib/puppet/functions/is_a.rb
@@ -0,0 +1,32 @@
+# Boolean check to determine whether a variable is of a given data type. This is equivalent to the `=~` type checks.
+#
+# @example how to check a data type
+# # check a data type
+# foo = 3
+# $bar = [1,2,3]
+# $baz = 'A string!'
+#
+# if $foo.is_a(Integer) {
+# notify { 'foo!': }
+# }
+# if $bar.is_a(Array) {
+# notify { 'bar!': }
+# }
+# if $baz.is_a(String) {
+# notify { 'baz!': }
+# }
+#
+# See the documentation for "The Puppet Type System" for more information about types.
+# See the `assert_type()` function for flexible ways to assert the type of a value.
+#
+Puppet::Functions.create_function(:is_a) do
+ dispatch :is_a do
+ param 'Any', :value
+ param 'Type', :type
+ end
+
+ def is_a(value, type)
+ # See puppet's lib/puppet/pops/evaluator/evaluator_impl.rb eval_MatchExpression
+ Puppet::Pops::Types::TypeCalculator.instance?(type, value)
+ end
+end
diff --git a/lib/puppet/parser/functions/bool2str.rb b/lib/puppet/parser/functions/bool2str.rb
index fcd3791..7e36474 100644
--- a/lib/puppet/parser/functions/bool2str.rb
+++ b/lib/puppet/parser/functions/bool2str.rb
@@ -4,15 +4,29 @@
module Puppet::Parser::Functions
newfunction(:bool2str, :type => :rvalue, :doc => <<-EOS
- Converts a boolean to a string.
+ Converts a boolean to a string using optionally supplied arguments. The
+ optional second and third arguments represent what true and false will be
+ converted to respectively. If only one argument is given, it will be
+ converted from a boolean to a string containing 'true' or 'false'.
+
+ *Examples:*
+
+ bool2str(true) => 'true'
+ bool2str(true, 'yes', 'no') => 'yes'
+ bool2str(false, 't', 'f') => 'f'
+
Requires a single boolean as an input.
EOS
) do |arguments|
- raise(Puppet::ParseError, "bool2str(): Wrong number of arguments " +
- "given (#{arguments.size} for 1)") if arguments.size < 1
+ unless arguments.size == 1 or arguments.size == 3
+ raise(Puppet::ParseError, "bool2str(): Wrong number of arguments " +
+ "given (#{arguments.size} for 3)")
+ end
value = arguments[0]
+ true_string = arguments[1] || 'true'
+ false_string = arguments[2] || 'false'
klass = value.class
# We can have either true or false, and nothing else
@@ -20,7 +34,11 @@ module Puppet::Parser::Functions
raise(Puppet::ParseError, 'bool2str(): Requires a boolean to work with')
end
- return value.to_s
+ unless [true_string, false_string].all?{|x| x.kind_of?(String)}
+ raise(Puppet::ParseError, "bool2str(): Requires strings to convert to" )
+ end
+
+ return value ? true_string : false_string
end
end
diff --git a/lib/puppet/parser/functions/empty.rb b/lib/puppet/parser/functions/empty.rb
index cca620f..b5a3cde 100644
--- a/lib/puppet/parser/functions/empty.rb
+++ b/lib/puppet/parser/functions/empty.rb
@@ -13,14 +13,18 @@ Returns true if the variable is empty.
value = arguments[0]
- unless value.is_a?(Array) || value.is_a?(Hash) || value.is_a?(String)
+ unless value.is_a?(Array) || value.is_a?(Hash) || value.is_a?(String) || value.is_a?(Numeric)
raise(Puppet::ParseError, 'empty(): Requires either ' +
- 'array, hash or string to work with')
+ 'array, hash, string or integer to work with')
end
- result = value.empty?
+ if value.is_a?(Numeric)
+ return false
+ else
+ result = value.empty?
- return result
+ return result
+ end
end
end
diff --git a/lib/puppet/parser/functions/intersection.rb b/lib/puppet/parser/functions/intersection.rb
index 48f02e9..bfbb4ba 100644
--- a/lib/puppet/parser/functions/intersection.rb
+++ b/lib/puppet/parser/functions/intersection.rb
@@ -4,13 +4,13 @@
module Puppet::Parser::Functions
newfunction(:intersection, :type => :rvalue, :doc => <<-EOS
-This function returns an array an intersection of two.
+This function returns an array of the intersection of two.
*Examples:*
- intersection(["a","b","c"],["b","c","d"])
+ intersection(["a","b","c"],["b","c","d"]) # returns ["b","c"]
+ intersection(["a","b","c"],[1,2,3,4]) # returns [] (true, when evaluated as a Boolean)
-Would return: ["b","c"]
EOS
) do |arguments|
diff --git a/lib/puppet/parser/functions/load_module_metadata.rb b/lib/puppet/parser/functions/load_module_metadata.rb
index 0664a23..c9b8488 100644
--- a/lib/puppet/parser/functions/load_module_metadata.rb
+++ b/lib/puppet/parser/functions/load_module_metadata.rb
@@ -2,14 +2,22 @@ module Puppet::Parser::Functions
newfunction(:load_module_metadata, :type => :rvalue, :doc => <<-EOT
EOT
) do |args|
- raise(Puppet::ParseError, "load_module_metadata(): Wrong number of arguments, expects one") unless args.size == 1
+ raise(Puppet::ParseError, "load_module_metadata(): Wrong number of arguments, expects one or two") unless [1,2].include?(args.size)
mod = args[0]
+ allow_empty_metadata = args[1]
module_path = function_get_module_path([mod])
metadata_json = File.join(module_path, 'metadata.json')
- raise(Puppet::ParseError, "load_module_metadata(): No metadata.json file for module #{mod}") unless File.exists?(metadata_json)
-
- metadata = PSON.load(File.read(metadata_json))
+ metadata_exists = File.exists?(metadata_json)
+ if metadata_exists
+ metadata = PSON.load(File.read(metadata_json))
+ else
+ if allow_empty_metadata
+ metadata = {}
+ else
+ raise(Puppet::ParseError, "load_module_metadata(): No metadata.json file for module #{mod}")
+ end
+ end
return metadata
end
diff --git a/lib/puppet/parser/functions/parsejson.rb b/lib/puppet/parser/functions/parsejson.rb
index a9a16a4..b4af40e 100644
--- a/lib/puppet/parser/functions/parsejson.rb
+++ b/lib/puppet/parser/functions/parsejson.rb
@@ -4,20 +4,25 @@
module Puppet::Parser::Functions
newfunction(:parsejson, :type => :rvalue, :doc => <<-EOS
-This function accepts JSON as a string and converts into the correct Puppet
-structure.
- EOS
+This function accepts JSON as a string and converts it into the correct
+Puppet structure.
+
+The optional second argument can be used to pass a default value that will
+be returned if the parsing of YAML string have failed.
+ EOS
) do |arguments|
+ raise ArgumentError, 'Wrong number of arguments. 1 or 2 arguments should be provided.' unless arguments.length >= 1
- if (arguments.size != 1) then
- raise(Puppet::ParseError, "parsejson(): Wrong number of arguments "+
- "given #{arguments.size} for 1")
+ begin
+ PSON::load(arguments[0]) || arguments[1]
+ rescue Exception => e
+ if arguments[1]
+ arguments[1]
+ else
+ raise e
+ end
end
- json = arguments[0]
-
- # PSON is natively available in puppet
- PSON.load(json)
end
end
diff --git a/lib/puppet/parser/functions/parseyaml.rb b/lib/puppet/parser/functions/parseyaml.rb
index 53d54fa..66d0413 100644
--- a/lib/puppet/parser/functions/parseyaml.rb
+++ b/lib/puppet/parser/functions/parseyaml.rb
@@ -6,17 +6,23 @@ module Puppet::Parser::Functions
newfunction(:parseyaml, :type => :rvalue, :doc => <<-EOS
This function accepts YAML as a string and converts it into the correct
Puppet structure.
- EOS
- ) do |arguments|
-
- if (arguments.size != 1) then
- raise(Puppet::ParseError, "parseyaml(): Wrong number of arguments "+
- "given #{arguments.size} for 1")
- end
+The optional second argument can be used to pass a default value that will
+be returned if the parsing of YAML string have failed.
+ EOS
+ ) do |arguments|
+ raise ArgumentError, 'Wrong number of arguments. 1 or 2 arguments should be provided.' unless arguments.length >= 1
require 'yaml'
- YAML::load(arguments[0])
+ begin
+ YAML::load(arguments[0]) || arguments[1]
+ rescue Exception => e
+ if arguments[1]
+ arguments[1]
+ else
+ raise e
+ end
+ end
end
end
diff --git a/lib/puppet/parser/functions/str2bool.rb b/lib/puppet/parser/functions/str2bool.rb
index 446732e..8def131 100644
--- a/lib/puppet/parser/functions/str2bool.rb
+++ b/lib/puppet/parser/functions/str2bool.rb
@@ -5,8 +5,8 @@
module Puppet::Parser::Functions
newfunction(:str2bool, :type => :rvalue, :doc => <<-EOS
This converts a string to a boolean. This attempt to convert strings that
-contain things like: y, 1, t, true to 'true' and strings that contain things
-like: 0, f, n, false, no to 'false'.
+contain things like: Y,y, 1, T,t, TRUE,true to 'true' and strings that contain things
+like: 0, F,f, N,n, false, FALSE, no to 'false'.
EOS
) do |arguments|
@@ -32,8 +32,8 @@ like: 0, f, n, false, no to 'false'.
# We yield false in this case.
#
when /^$/, '' then false # Empty string will be false ...
- when /^(1|t|y|true|yes)$/ then true
- when /^(0|f|n|false|no)$/ then false
+ when /^(1|t|y|true|yes)$/i then true
+ when /^(0|f|n|false|no)$/i then false
when /^(undef|undefined)$/ then false # This is not likely to happen ...
else
raise(Puppet::ParseError, 'str2bool(): Unknown type of boolean given')
diff --git a/lib/puppet/parser/functions/validate_ip_address.rb b/lib/puppet/parser/functions/validate_ip_address.rb
new file mode 100644
index 0000000..c0baf82
--- /dev/null
+++ b/lib/puppet/parser/functions/validate_ip_address.rb
@@ -0,0 +1,50 @@
+module Puppet::Parser::Functions
+
+ newfunction(:validate_ip_address, :doc => <<-ENDHEREDOC
+ Validate that all values passed are valid IP addresses,
+ regardless they are IPv4 or IPv6
+ Fail compilation if any value fails this check.
+ The following values will pass:
+ $my_ip = "1.2.3.4"
+ validate_ip_address($my_ip)
+ validate_bool("8.8.8.8", "172.16.0.1", $my_ip)
+
+ $my_ip = "3ffe:505:2"
+ validate_ip_address(1)
+ validate_ip_address($my_ip)
+ validate_bool("fe80::baf6:b1ff:fe19:7507", $my_ip)
+
+ The following values will fail, causing compilation to abort:
+ $some_array = [ 1, true, false, "garbage string", "3ffe:505:2" ]
+ validate_ip_address($some_array)
+ ENDHEREDOC
+ ) do |args|
+
+ require "ipaddr"
+ rescuable_exceptions = [ ArgumentError ]
+
+ if defined?(IPAddr::InvalidAddressError)
+ rescuable_exceptions << IPAddr::InvalidAddressError
+ end
+
+ unless args.length > 0 then
+ raise Puppet::ParseError, ("validate_ip_address(): wrong number of arguments (#{args.length}; must be > 0)")
+ end
+
+ args.each do |arg|
+ unless arg.is_a?(String)
+ raise Puppet::ParseError, "#{arg.inspect} is not a string."
+ end
+
+ begin
+ unless IPAddr.new(arg).ipv4? or IPAddr.new(arg).ipv6?
+ raise Puppet::ParseError, "#{arg.inspect} is not a valid IP address."
+ end
+ rescue *rescuable_exceptions
+ raise Puppet::ParseError, "#{arg.inspect} is not a valid IP address."
+ end
+ end
+
+ end
+
+end
diff --git a/lib/puppet/parser/functions/validate_ipv4_address.rb b/lib/puppet/parser/functions/validate_ipv4_address.rb
index fc02748..97faa57 100644
--- a/lib/puppet/parser/functions/validate_ipv4_address.rb
+++ b/lib/puppet/parser/functions/validate_ipv4_address.rb
@@ -8,7 +8,7 @@ module Puppet::Parser::Functions
$my_ip = "1.2.3.4"
validate_ipv4_address($my_ip)
- validate_bool("8.8.8.8", "172.16.0.1", $my_ip)
+ validate_ipv4_address("8.8.8.8", "172.16.0.1", $my_ip)
The following values will fail, causing compilation to abort:
diff --git a/lib/puppet/parser/functions/validate_re.rb b/lib/puppet/parser/functions/validate_re.rb
index ca25a70..efee7f8 100644
--- a/lib/puppet/parser/functions/validate_re.rb
+++ b/lib/puppet/parser/functions/validate_re.rb
@@ -23,16 +23,23 @@ module Puppet::Parser::Functions
validate_re($::puppetversion, '^2.7', 'The $puppetversion fact value does not match 2.7')
+ Note: Compilation will also abort, if the first argument is not a String. Always use
+ quotes to force stringification:
+
+ validate_re("${::operatingsystemmajrelease}", '^[57]$')
+
ENDHEREDOC
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)")
+ raise Puppet::ParseError, "validate_re(): wrong number of arguments (#{args.length}; must be 2 or 3)"
end
+ raise Puppet::ParseError, "validate_re(): input needs to be a String, not a #{args[0].class}" unless args[0].is_a? String
+
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|
+ raise Puppet::ParseError, msg unless [args[1]].flatten.any? do |re_str|
args[0] =~ Regexp.compile(re_str)
end
diff --git a/lib/puppet/type/file_line.rb b/lib/puppet/type/file_line.rb
index 446f103..77d3be2 100644
--- a/lib/puppet/type/file_line.rb
+++ b/lib/puppet/type/file_line.rb
@@ -4,7 +4,7 @@ Puppet::Type.newtype(:file_line) do
Ensures that a given line is contained within a file. The implementation
matches the full line, including whitespace at the beginning and end. If
the line is not contained in the given file, Puppet will append the line to
- the end of the file to ensure the desired state. Multiple resources may
+ the end of the file to ensure the desired state. Multiple resources may
be declared to manage multiple lines in the same file.
Example:
@@ -31,7 +31,7 @@ Puppet::Type.newtype(:file_line) do
match => '^export\ HTTP_PROXY\=',
}
- In this code example match will look for a line beginning with export
+ In this code example match will look for a line beginning with export
followed by HTTP_PROXY and replace it with the value in line.
Match Example With `ensure => absent`:
@@ -50,7 +50,6 @@ Puppet::Type.newtype(:file_line) do
**Autorequires:** If Puppet is managing the file that will contain the line
being managed, the file_line resource will autorequire that file.
-
EOT
ensurable do
@@ -63,10 +62,10 @@ Puppet::Type.newtype(:file_line) do
end
newparam(:match) do
- desc 'An optional ruby regular expression to run against existing lines in the file.' +
+ desc 'An optional ruby regular expression to run against existing lines in the file.' +
' If a match is found, we replace that line rather than adding a new line.' +
- ' A regex comparisson is performed against the line value and if it does not' +
- ' match an exception will be raised. '
+ ' A regex comparison is performed against the line value and if it does not' +
+ ' match an exception will be raised.'
end
newparam(:match_for_absence) do
diff --git a/manifests/stages.pp b/manifests/stages.pp
index eb15fd6..7de254c 100644
--- a/manifests/stages.pp
+++ b/manifests/stages.pp
@@ -26,7 +26,7 @@
# Sample Usage:
#
# node default {
-# include stdlib
+# include ::stdlib
# class { java: stage => 'runtime' }
# }
#
diff --git a/spec/acceptance/empty_spec.rb b/spec/acceptance/empty_spec.rb
index 8b46aac..2d4df90 100755
--- a/spec/acceptance/empty_spec.rb
+++ b/spec/acceptance/empty_spec.rb
@@ -31,6 +31,20 @@ describe 'empty function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('opera
expect(r.stdout).to match(/Notice: output correct/)
end
end
+ it 'handles numerical values' do
+ pp = <<-EOS
+ $a = 7
+ $b = false
+ $o = empty($a)
+ if $o == $b {
+ notify { 'output correct': }
+ }
+ EOS
+
+ apply_manifest(pp, :catch_failures => true) do |r|
+ expect(r.stdout).to match(/Notice: output correct/)
+ end
+ end
end
describe 'failure' do
it 'handles improper argument counts'
diff --git a/spec/acceptance/is_a_spec.rb b/spec/acceptance/is_a_spec.rb
new file mode 100644
index 0000000..355fd83
--- /dev/null
+++ b/spec/acceptance/is_a_spec.rb
@@ -0,0 +1,30 @@
+#! /usr/bin/env ruby -S rspec
+require 'spec_helper_acceptance'
+
+if get_puppet_version =~ /^4/
+ describe 'is_a function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
+ it 'should match a string' do
+ pp = <<-EOS
+ if 'hello world'.is_a(String) {
+ notify { 'output correct': }
+ }
+ EOS
+
+ apply_manifest(pp, :catch_failures => true) do |r|
+ expect(r.stdout).to match(/Notice: output correct/)
+ end
+ end
+
+ it 'should not match a integer as string' do
+ pp = <<-EOS
+ if 5.is_a(String) {
+ notify { 'output wrong': }
+ }
+ EOS
+
+ apply_manifest(pp, :catch_failures => true) do |r|
+ expect(r.stdout).not_to match(/Notice: output wrong/)
+ end
+ end
+ end
+end
diff --git a/spec/acceptance/parsejson_spec.rb b/spec/acceptance/parsejson_spec.rb
index 5097810..d0e3de8 100755
--- a/spec/acceptance/parsejson_spec.rb
+++ b/spec/acceptance/parsejson_spec.rb
@@ -16,10 +16,23 @@ describe 'parsejson function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('o
end
end
end
+
describe 'failure' do
it 'raises error on incorrect json' do
pp = <<-EOS
$a = '{"hunter": "washere", "tests": "passing",}'
+ $ao = parsejson($a, 'tests are using the default value')
+ notice(inline_template('a is <%= @ao.inspect %>'))
+ EOS
+
+ apply_manifest(pp, :catch_failures => true) do |r|
+ expect(r.stdout).to match(/tests are using the default value/)
+ end
+ end
+
+ it 'raises error on incorrect json' do
+ pp = <<-EOS
+ $a = '{"hunter": "washere", "tests": "passing",}'
$ao = parsejson($a)
notice(inline_template('a is <%= @ao.inspect %>'))
EOS
@@ -29,6 +42,14 @@ describe 'parsejson function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('o
end
end
- it 'raises error on incorrect number of arguments'
+ it 'raises error on incorrect number of arguments' do
+ pp = <<-EOS
+ $o = parsejson()
+ EOS
+
+ apply_manifest(pp, :expect_failures => true) do |r|
+ expect(r.stderr).to match(/wrong number of arguments/i)
+ end
+ end
end
end
diff --git a/spec/acceptance/parseyaml_spec.rb b/spec/acceptance/parseyaml_spec.rb
index 5819837..64511f1 100755
--- a/spec/acceptance/parseyaml_spec.rb
+++ b/spec/acceptance/parseyaml_spec.rb
@@ -16,7 +16,21 @@ describe 'parseyaml function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('o
end
end
end
+
describe 'failure' do
+ it 'returns the default value on incorrect yaml' do
+ pp = <<-EOS
+ $a = "---\nhunter: washere\ntests: passing\n:"
+ $o = parseyaml($a, {'tests' => 'using the default value'})
+ $tests = $o['tests']
+ notice(inline_template('tests are <%= @tests.inspect %>'))
+ EOS
+
+ apply_manifest(pp, :catch_failures => true) do |r|
+ expect(r.stdout).to match(/tests are "using the default value"/)
+ end
+ end
+
it 'raises error on incorrect yaml' do
pp = <<-EOS
$a = "---\nhunter: washere\ntests: passing\n:"
@@ -30,6 +44,15 @@ describe 'parseyaml function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('o
end
end
- it 'raises error on incorrect number of arguments'
+
+ it 'raises error on incorrect number of arguments' do
+ pp = <<-EOS
+ $o = parseyaml()
+ EOS
+
+ apply_manifest(pp, :expect_failures => true) do |r|
+ expect(r.stderr).to match(/wrong number of arguments/i)
+ end
+ end
end
end
diff --git a/spec/functions/bool2str_spec.rb b/spec/functions/bool2str_spec.rb
index 8d35598..23a754b 100755
--- a/spec/functions/bool2str_spec.rb
+++ b/spec/functions/bool2str_spec.rb
@@ -6,6 +6,12 @@ describe 'bool2str' do
[ 'true', 'false', nil, :undef, ''].each do |invalid|
it { is_expected.to run.with_params(invalid).and_raise_error(Puppet::ParseError) }
end
+ it { is_expected.to run.with_params(true, 'yes', 'no', 'maybe').and_raise_error(Puppet::ParseError) }
+ it { is_expected.to run.with_params(true, 'maybe').and_raise_error(Puppet::ParseError) }
+ it { is_expected.to run.with_params(true, 0, 1).and_raise_error(Puppet::ParseError) }
it { is_expected.to run.with_params(true).and_return("true") }
it { is_expected.to run.with_params(false).and_return("false") }
+ it { is_expected.to run.with_params(true, 'yes', 'no').and_return("yes") }
+ it { is_expected.to run.with_params(false, 'yes', 'no').and_return("no") }
+
end
diff --git a/spec/functions/empty_spec.rb b/spec/functions/empty_spec.rb
index 94b1c68..a3a25d6 100755
--- a/spec/functions/empty_spec.rb
+++ b/spec/functions/empty_spec.rb
@@ -3,11 +3,11 @@ require 'spec_helper'
describe 'empty' do
it { is_expected.not_to eq(nil) }
it { is_expected.to run.with_params().and_raise_error(Puppet::ParseError) }
- it { is_expected.to run.with_params(0).and_raise_error(Puppet::ParseError) }
it {
pending("Current implementation ignores parameters after the first.")
is_expected.to run.with_params('one', 'two').and_raise_error(Puppet::ParseError)
}
+ it { is_expected.to run.with_params(0).and_return(false) }
it { is_expected.to run.with_params('').and_return(true) }
it { is_expected.to run.with_params('one').and_return(false) }
diff --git a/spec/functions/is_a_spec.rb b/spec/functions/is_a_spec.rb
new file mode 100644
index 0000000..8dec13f
--- /dev/null
+++ b/spec/functions/is_a_spec.rb
@@ -0,0 +1,25 @@
+require 'spec_helper'
+
+if ENV["FUTURE_PARSER"] == 'yes'
+ describe 'type_of' do
+ pending 'teach rspec-puppet to load future-only functions under 3.7.5' do
+ it { is_expected.not_to eq(nil) }
+ end
+ end
+end
+
+if Puppet.version.to_f >= 4.0
+ describe 'is_a' do
+ it { is_expected.not_to eq(nil) }
+ it { is_expected.to run.with_params().and_raise_error(ArgumentError) }
+ it { is_expected.to run.with_params('', '').and_raise_error(ArgumentError) }
+
+ it 'succeeds when comparing a string and a string' do
+ is_expected.to run.with_params('hello world', String).and_return(true)
+ end
+
+ it 'fails when comparing an integer and a string' do
+ is_expected.to run.with_params(5, String).and_return(false)
+ end
+ end
+end
diff --git a/spec/functions/load_module_metadata.rb b/spec/functions/load_module_metadata.rb
deleted file mode 100755
index ba542eb..0000000
--- a/spec/functions/load_module_metadata.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-require 'spec_helper'
-
-describe 'load_module_metadata' do
- it { is_expected.not_to eq(nil) }
- it { is_expected.to run.with_params().and_raise_error(Puppet::ParseError, /wrong number of arguments/i) }
- it { is_expected.to run.with_params("one", "two").and_raise_error(Puppet::ParseError, /wrong number of arguments/i) }
-
- it "should json parse the file" do
- allow(scope).to receive(:function_get_module_path).with(['science']).and_return('/path/to/module/')
- allow(File).to receive(:exists?).with(/metadata.json/).and_return(true)
- allow(File).to receive(:read).with(/metadata.json/).and_return('{"name": "spencer-science"}')
-
- result = subject.call(['science'])
- expect(result['name']).to eq('spencer-science')
- end
-end
diff --git a/spec/functions/load_module_metadata_spec.rb b/spec/functions/load_module_metadata_spec.rb
new file mode 100755
index 0000000..fe665fb
--- /dev/null
+++ b/spec/functions/load_module_metadata_spec.rb
@@ -0,0 +1,29 @@
+require 'spec_helper'
+
+describe 'load_module_metadata' do
+ it { is_expected.not_to eq(nil) }
+ it { is_expected.to run.with_params().and_raise_error(Puppet::ParseError, /wrong number of arguments/i) }
+ it { is_expected.to run.with_params("one", "two", "three").and_raise_error(Puppet::ParseError, /wrong number of arguments/i) }
+
+ it "should json parse the file" do
+ allow(scope).to receive(:function_get_module_path).with(['science']).and_return('/path/to/module/')
+ allow(File).to receive(:exists?).with(/metadata.json/).and_return(true)
+ allow(File).to receive(:read).with(/metadata.json/).and_return('{"name": "spencer-science"}')
+
+ result = subject.call(['science'])
+ expect(result['name']).to eq('spencer-science')
+ end
+
+ it "should fail by default if there is no metadata.json" do
+ allow(scope).to receive(:function_get_module_path).with(['science']).and_return('/path/to/module/')
+ allow(File).to receive(:exists?).with(/metadata.json/).and_return(false)
+ expect {subject.call(['science'])}.to raise_error(Puppet::ParseError)
+ end
+
+ it "should return nil if user allows empty metadata.json" do
+ allow(scope).to receive(:function_get_module_path).with(['science']).and_return('/path/to/module/')
+ allow(File).to receive(:exists?).with(/metadata.json/).and_return(false)
+ result = subject.call(['science', true])
+ expect(result).to eq({})
+ end
+end
diff --git a/spec/functions/parsejson_spec.rb b/spec/functions/parsejson_spec.rb
index 436566e..a01f1f6 100755
--- a/spec/functions/parsejson_spec.rb
+++ b/spec/functions/parsejson_spec.rb
@@ -1,9 +1,64 @@
require 'spec_helper'
describe 'parsejson' do
- it { is_expected.not_to eq(nil) }
- it { is_expected.to run.with_params().and_raise_error(Puppet::ParseError, /wrong number of arguments/i) }
- it { is_expected.to run.with_params('', '').and_raise_error(Puppet::ParseError, /wrong number of arguments/i) }
- it { is_expected.to run.with_params('["one"').and_raise_error(PSON::ParserError) }
- it { is_expected.to run.with_params('["one", "two", "three"]').and_return(['one', 'two', 'three']) }
+ it 'should exist' do
+ is_expected.not_to eq(nil)
+ end
+
+ it 'should raise an error if called without any arguments' do
+ is_expected.to run.with_params().
+ and_raise_error(/wrong number of arguments/i)
+ end
+
+ context 'with correct JSON data' do
+
+ it 'should be able to parse a JSON data with a Hash' do
+ is_expected.to run.with_params('{"a":"1","b":"2"}').
+ and_return({'a'=>'1', 'b'=>'2'})
+ end
+
+ it 'should be able to parse a JSON data with an Array' do
+ is_expected.to run.with_params('["a","b","c"]').
+ and_return(['a', 'b', 'c'])
+ end
+
+ it 'should be able to parse empty JSON values' do
+ is_expected.to run.with_params('[]').
+ and_return([])
+ is_expected.to run.with_params('{}').
+ and_return({})
+ end
+
+ it 'should be able to parse a JSON data with a mixed structure' do
+ is_expected.to run.with_params('{"a":"1","b":2,"c":{"d":[true,false]}}').
+ and_return({'a' =>'1', 'b' => 2, 'c' => { 'd' => [true, false] } })
+ end
+
+ it 'should not return the default value if the data was parsed correctly' do
+ is_expected.to run.with_params('{"a":"1"}', 'default_value').
+ and_return({'a' => '1'})
+ end
+
+ end
+
+ context 'with incorrect JSON data' do
+ it 'should raise an error with invalid JSON and no default' do
+ is_expected.to run.with_params('').
+ and_raise_error(PSON::ParserError)
+ end
+
+ it 'should support a structure for a default value' do
+ is_expected.to run.with_params('', {'a' => '1'}).
+ and_return({'a' => '1'})
+ end
+
+ ['', 1, 1.2, nil, true, false, [], {}, :yaml].each do |value|
+ it "should return the default value for an incorrect #{value.inspect} (#{value.class}) parameter" do
+ is_expected.to run.with_params(value, 'default_value').
+ and_return('default_value')
+ end
+ end
+
+ end
+
end
diff --git a/spec/functions/parseyaml_spec.rb b/spec/functions/parseyaml_spec.rb
index fb635f8..fa947ca 100755
--- a/spec/functions/parseyaml_spec.rb
+++ b/spec/functions/parseyaml_spec.rb
@@ -1,14 +1,81 @@
require 'spec_helper'
describe 'parseyaml' do
- it { is_expected.not_to eq(nil) }
- it { is_expected.to run.with_params().and_raise_error(Puppet::ParseError, /wrong number of arguments/i) }
- it { is_expected.to run.with_params('', '').and_raise_error(Puppet::ParseError, /wrong number of arguments/i) }
- it { is_expected.to run.with_params('["one", "two", "three"]').and_return(['one', 'two', 'three']) }
- context 'when running on modern rubies', :unless => RUBY_VERSION == '1.8.7' do
- it { is_expected.to run.with_params('["one"').and_raise_error(Psych::SyntaxError) }
+ it 'should exist' do
+ is_expected.not_to eq(nil)
end
- context 'when running on ruby 1.8.7, which does not have Psych', :if => RUBY_VERSION == '1.8.7' do
- it { is_expected.to run.with_params('["one"').and_raise_error(ArgumentError) }
+
+ it 'should raise an error if called without any arguments' do
+ is_expected.to run.with_params().
+ and_raise_error(/wrong number of arguments/i)
end
+
+ context 'with correct YAML data' do
+ it 'should be able to parse a YAML data with a String' do
+ is_expected.to run.with_params('--- just a string').
+ and_return('just a string')
+ is_expected.to run.with_params('just a string').
+ and_return('just a string')
+ end
+
+ it 'should be able to parse a YAML data with a Hash' do
+ is_expected.to run.with_params("---\na: '1'\nb: '2'\n").
+ and_return({'a' => '1', 'b' => '2'})
+ end
+
+ it 'should be able to parse a YAML data with an Array' do
+ is_expected.to run.with_params("---\n- a\n- b\n- c\n").
+ and_return(['a', 'b', 'c'])
+ end
+
+ it 'should be able to parse a YAML data with a mixed structure' do
+ is_expected.to run.with_params("---\na: '1'\nb: 2\nc:\n d:\n - :a\n - true\n - false\n").
+ and_return({'a' => '1', 'b' => 2, 'c' => {'d' => [:a, true, false]}})
+ end
+
+ it 'should not return the default value if the data was parsed correctly' do
+ is_expected.to run.with_params("---\na: '1'\n", 'default_value').
+ and_return({'a' => '1'})
+ end
+
+ end
+
+ context 'on a modern ruby', :unless => RUBY_VERSION == '1.8.7' do
+ it 'should raise an error with invalid YAML and no default' do
+ is_expected.to run.with_params('["one"').
+ and_raise_error(Psych::SyntaxError)
+ end
+ end
+
+ context 'when running on ruby 1.8.7, which does not have Psych', :if => RUBY_VERSION == '1.8.7' do
+ it 'should raise an error with invalid YAML and no default' do
+ is_expected.to run.with_params('["one"').
+ and_raise_error(ArgumentError)
+ end
+ end
+
+ context 'with incorrect YAML data' do
+ it 'should support a structure for a default value' do
+ is_expected.to run.with_params('', {'a' => '1'}).
+ and_return({'a' => '1'})
+ end
+
+ [1, 1.2, nil, true, false, [], {}, :yaml].each do |value|
+ it "should return the default value for an incorrect #{value.inspect} (#{value.class}) parameter" do
+ is_expected.to run.with_params(value, 'default_value').
+ and_return('default_value')
+ end
+ end
+
+ context 'when running on modern rubies', :unless => RUBY_VERSION == '1.8.7' do
+ ['---', '...', '*8', ''].each do |value|
+ it "should return the default value for an incorrect #{value.inspect} string parameter" do
+ is_expected.to run.with_params(value, 'default_value').
+ and_return('default_value')
+ end
+ end
+ end
+
+ end
+
end
diff --git a/spec/functions/str2bool_spec.rb b/spec/functions/str2bool_spec.rb
index 3b439b2..7d8c47c 100755
--- a/spec/functions/str2bool_spec.rb
+++ b/spec/functions/str2bool_spec.rb
@@ -10,13 +10,13 @@ describe 'str2bool' do
it { is_expected.to run.with_params('one').and_raise_error(Puppet::ParseError, /Unknown type of boolean given/) }
describe 'when testing values that mean "true"' do
- [ '1', 't', 'y', 'true', 'yes', true ].each do |value|
+ [ 'TRUE','1', 't', 'y', 'true', 'yes', true ].each do |value|
it { is_expected.to run.with_params(value).and_return(true) }
end
end
describe 'when testing values that mean "false"' do
- [ '', '0', 'f', 'n', 'false', 'no', false, 'undef', 'undefined' ].each do |value|
+ [ 'FALSE','', '0', 'f', 'n', 'false', 'no', false, 'undef', 'undefined' ].each do |value|
it { is_expected.to run.with_params(value).and_return(false) }
end
end
diff --git a/spec/functions/type_of_spec.rb b/spec/functions/type_of_spec.rb
index f770990..cc9ef78 100644
--- a/spec/functions/type_of_spec.rb
+++ b/spec/functions/type_of_spec.rb
@@ -2,7 +2,9 @@ require 'spec_helper'
if ENV["FUTURE_PARSER"] == 'yes'
describe 'type_of' do
- pending 'teach rspec-puppet to load future-only functions under 3.7.5'
+ pending 'teach rspec-puppet to load future-only functions under 3.7.5' do
+ it { is_expected.not_to eq(nil) }
+ end
end
end
diff --git a/spec/functions/validate_ip_address_spec.rb b/spec/functions/validate_ip_address_spec.rb
new file mode 100644
index 0000000..b56ce51
--- /dev/null
+++ b/spec/functions/validate_ip_address_spec.rb
@@ -0,0 +1,46 @@
+require 'spec_helper'
+
+describe 'validate_ip_address' do
+ describe 'signature validation' do
+ it { is_expected.not_to eq(nil) }
+ it { is_expected.to run.with_params().and_raise_error(Puppet::ParseError, /wrong number of arguments/i) }
+ end
+
+ describe 'valid inputs' do
+ it { is_expected.to run.with_params('0.0.0.0') }
+ it { is_expected.to run.with_params('8.8.8.8') }
+ it { is_expected.to run.with_params('127.0.0.1') }
+ it { is_expected.to run.with_params('10.10.10.10') }
+ it { is_expected.to run.with_params('194.232.104.150') }
+ it { is_expected.to run.with_params('244.24.24.24') }
+ it { is_expected.to run.with_params('255.255.255.255') }
+ it { is_expected.to run.with_params('1.2.3.4', '5.6.7.8') }
+ it { is_expected.to run.with_params('3ffe:0505:0002::') }
+ it { is_expected.to run.with_params('3ffe:0505:0002::', '3ffe:0505:0002::2') }
+ it { is_expected.to run.with_params('::1/64') }
+ it { is_expected.to run.with_params('fe80::a00:27ff:fe94:44d6/64') }
+ context 'with netmasks' do
+ it { is_expected.to run.with_params('8.8.8.8/0') }
+ it { is_expected.to run.with_params('8.8.8.8/16') }
+ it { is_expected.to run.with_params('8.8.8.8/32') }
+ it { is_expected.to run.with_params('8.8.8.8/255.255.0.0') }
+ end
+ end
+
+ describe 'invalid inputs' do
+ it { is_expected.to run.with_params({}).and_raise_error(Puppet::ParseError, /is not a string/) }
+ it { is_expected.to run.with_params(1).and_raise_error(Puppet::ParseError, /is not a string/) }
+ it { is_expected.to run.with_params(true).and_raise_error(Puppet::ParseError, /is not a string/) }
+ it { is_expected.to run.with_params('one').and_raise_error(Puppet::ParseError, /is not a valid IP/) }
+ it { is_expected.to run.with_params('0.0.0').and_raise_error(Puppet::ParseError, /is not a valid IP/) }
+ it { is_expected.to run.with_params('0.0.0.256').and_raise_error(Puppet::ParseError, /is not a valid IP/) }
+ it { is_expected.to run.with_params('0.0.0.0.0').and_raise_error(Puppet::ParseError, /is not a valid IP/) }
+ it { is_expected.to run.with_params('1.2.3.4', {}).and_raise_error(Puppet::ParseError, /is not a string/) }
+ it { is_expected.to run.with_params('1.2.3.4', 1).and_raise_error(Puppet::ParseError, /is not a string/) }
+ it { is_expected.to run.with_params('1.2.3.4', true).and_raise_error(Puppet::ParseError, /is not a string/) }
+ it { is_expected.to run.with_params('1.2.3.4', 'one').and_raise_error(Puppet::ParseError, /is not a valid IP/) }
+ it { is_expected.to run.with_params('::1', {}).and_raise_error(Puppet::ParseError, /is not a string/) }
+ it { is_expected.to run.with_params('::1', true).and_raise_error(Puppet::ParseError, /is not a string/) }
+ it { is_expected.to run.with_params('::1', 'one').and_raise_error(Puppet::ParseError, /is not a valid IP/) }
+ end
+end
diff --git a/spec/functions/validate_re_spec.rb b/spec/functions/validate_re_spec.rb
index 42b1049..3f90143 100755
--- a/spec/functions/validate_re_spec.rb
+++ b/spec/functions/validate_re_spec.rb
@@ -41,6 +41,21 @@ describe 'validate_re' do
it { is_expected.to run.with_params('notone', '^one').and_raise_error(Puppet::ParseError, /does not match/) }
it { is_expected.to run.with_params('notone', [ '^one', '^two' ]).and_raise_error(Puppet::ParseError, /does not match/) }
it { is_expected.to run.with_params('notone', [ '^one', '^two' ], 'custom error').and_raise_error(Puppet::ParseError, /custom error/) }
+
+ describe 'non-string inputs' do
+ [
+ 1, # Fixnum
+ 3.14, # Float
+ nil, # NilClass
+ true, # TrueClass
+ false, # FalseClass
+ ["10"], # Array
+ :key, # Symbol
+ {:key=>"val"}, # Hash
+ ].each do |input|
+ it { is_expected.to run.with_params(input, '.*').and_raise_error(Puppet::ParseError, /needs to be a String/) }
+ end
+ end
end
end
end
diff --git a/spec/spec_helper_acceptance.rb b/spec/spec_helper_acceptance.rb
index f784112..eda0d1a 100755
--- a/spec/spec_helper_acceptance.rb
+++ b/spec/spec_helper_acceptance.rb
@@ -33,9 +33,13 @@ def is_future_parser_enabled?
return false
end
+def get_puppet_version
+ (on default, puppet('--version')).output.chomp
+end
+
RSpec.shared_context "with faked facts" do
let(:facts_d) do
- puppet_version = (on default, puppet('--version')).output.chomp
+ puppet_version = get_puppet_version
if fact('osfamily') =~ /windows/i
if fact('kernelmajversion').to_f < 6.0
'C:/Documents and Settings/All Users/Application Data/PuppetLabs/facter/facts.d'
diff --git a/spec/unit/facter/package_provider_spec.rb b/spec/unit/facter/package_provider_spec.rb
new file mode 100644
index 0000000..d1aee94
--- /dev/null
+++ b/spec/unit/facter/package_provider_spec.rb
@@ -0,0 +1,37 @@
+#! /usr/bin/env ruby -S rspec
+require 'spec_helper'
+require 'puppet/type'
+require 'puppet/type/package'
+
+describe 'package_provider', :type => :fact do
+ before { Facter.clear }
+ after { Facter.clear }
+
+ context "darwin" do
+ it "should return pkgdmg" do
+ provider = Puppet::Type.type(:package).provider(:pkgdmg)
+ Puppet::Type.type(:package).stubs(:defaultprovider).returns provider
+
+ expect(Facter.fact(:package_provider).value).to eq('pkgdmg')
+ end
+ end
+
+ context "centos 7" do
+ it "should return yum" do
+ provider = Puppet::Type.type(:package).provider(:yum)
+ Puppet::Type.type(:package).stubs(:defaultprovider).returns provider
+
+ expect(Facter.fact(:package_provider).value).to eq('yum')
+ end
+ end
+
+ context "ubuntu" do
+ it "should return apt" do
+ provider = Puppet::Type.type(:package).provider(:apt)
+ Puppet::Type.type(:package).stubs(:defaultprovider).returns provider
+
+ expect(Facter.fact(:package_provider).value).to eq('apt')
+ end
+ end
+
+end
diff --git a/spec/unit/facter/pe_version_spec.rb b/spec/unit/facter/pe_version_spec.rb
index 4d0349e..c11a1cd 100755
--- a/spec/unit/facter/pe_version_spec.rb
+++ b/spec/unit/facter/pe_version_spec.rb
@@ -14,6 +14,17 @@ describe "PE Version specs" do
Facter.collection.loader.load(:pe_version)
end
end
+
+ context "When puppetversion is nil" do
+ before :each do
+ Facter.fact(:puppetversion).stubs(:value).returns(nil)
+ end
+
+ it "pe_version is nil" do
+ expect(Facter.fact(:puppetversion).value).to be_nil
+ expect(Facter.fact(:pe_version).value).to be_nil
+ end
+ end
context "If PE is installed" do
%w{ 2.6.1 2.10.300 }.each do |version|
@@ -73,4 +84,5 @@ describe "PE Version specs" do
expect(Facter.fact(:pe_patch_version).value).to be_nil
end
end
+
end
diff --git a/spec/unit/facter/root_home_spec.rb b/spec/unit/facter/root_home_spec.rb
index ac5160a..a5c2846 100755
--- a/spec/unit/facter/root_home_spec.rb
+++ b/spec/unit/facter/root_home_spec.rb
@@ -58,7 +58,7 @@ describe 'root_home', :type => :fact do
sample_lsuser = File.read(fixtures('lsuser','root'))
it "should return /root" do
- Facter::Util::Resolution.stubs(:exec).with("lsuser -C -a home root").returns(sample_lsuser)
+ Facter::Util::Resolution.stubs(:exec).with("lsuser -c -a home root").returns(sample_lsuser)
expect(Facter.fact(:root_home).value).to eq(expected_root_home)
end
end
diff --git a/spec/unit/facter/service_provider_spec.rb b/spec/unit/facter/service_provider_spec.rb
new file mode 100644
index 0000000..ad8a5fc
--- /dev/null
+++ b/spec/unit/facter/service_provider_spec.rb
@@ -0,0 +1,37 @@
+#! /usr/bin/env ruby -S rspec
+require 'spec_helper'
+require 'puppet/type'
+require 'puppet/type/service'
+
+describe 'service_provider', :type => :fact do
+ before { Facter.clear }
+ after { Facter.clear }
+
+ context "macosx" do
+ it "should return launchd" do
+ provider = Puppet::Type.type(:service).provider(:launchd)
+ Puppet::Type.type(:service).stubs(:defaultprovider).returns provider
+
+ expect(Facter.fact(:service_provider).value).to eq('launchd')
+ end
+ end
+
+ context "systemd" do
+ it "should return systemd" do
+ provider = Puppet::Type.type(:service).provider(:systemd)
+ Puppet::Type.type(:service).stubs(:defaultprovider).returns provider
+
+ expect(Facter.fact(:service_provider).value).to eq('systemd')
+ end
+ end
+
+ context "redhat" do
+ it "should return redhat" do
+ provider = Puppet::Type.type(:service).provider(:redhat)
+ Puppet::Type.type(:service).stubs(:defaultprovider).returns provider
+
+ expect(Facter.fact(:service_provider).value).to eq('redhat')
+ end
+ end
+
+end