diff options
32 files changed, 953 insertions, 87 deletions
diff --git a/.gemspec b/.gemspec new file mode 100644 index 0000000..e274950 --- /dev/null +++ b/.gemspec @@ -0,0 +1,40 @@ +# +# -*- encoding: utf-8 -*- + +Gem::Specification.new do |s| + s.name = "puppetmodule-stdlib" + + s.version = "4.0.2" + + s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= + s.authors = ["Puppet Labs"] + s.date = "2013-04-12" + s.description = [ 'This Gem format of the stdlib module is intended to make', + 'it easier for _module authors_ to resolve dependencies', + 'using a Gemfile when running automated testing jobs like', + 'Travis or Jenkins. The recommended best practice for', + 'installation by end users is to use the `puppet module', + 'install` command to install stdlib from the [Puppet', + 'Forge](http://forge.puppetlabs.com/puppetlabs/stdlib).' ].join(' ') + s.email = "puppet-dev@puppetlabs.com" + s.executables = [] + s.files = [ 'CHANGELOG', 'CONTRIBUTING.md', 'Gemfile', 'LICENSE', 'Modulefile', + 'README.markdown', 'README_DEVELOPER.markdown', 'RELEASE_PROCESS.markdown', + 'Rakefile', 'spec/spec.opts' ] + s.files += Dir['lib/**/*.rb'] + Dir['manifests/**/*.pp'] + Dir['tests/**/*.pp'] + Dir['spec/**/*.rb'] + s.homepage = "http://forge.puppetlabs.com/puppetlabs/stdlib" + s.rdoc_options = ["--title", "Puppet Standard Library Development Gem", "--main", "README.markdown", "--line-numbers"] + s.require_paths = ["lib"] + s.rubyforge_project = "puppetmodule-stdlib" + s.rubygems_version = "1.8.24" + s.summary = "This gem provides a way to make the standard library available for other module spec testing tasks." + + if s.respond_to? :specification_version then + s.specification_version = 3 + + if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then + else + end + else + end +end @@ -2,6 +2,7 @@ pkg/ .DS_Store metadata.json coverage/ -vendor/ -.bundle/ +spec/fixtures/ Gemfile.lock +.bundle/ +vendor/bundle/ diff --git a/.travis.yml b/.travis.yml index df58d5a..1bb1889 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,20 +1,19 @@ language: ruby bundler_args: --without development -script: "bundle exec rake spec SPEC_OPTS='--format documentation'" +script: "bundle exec rake spec SPEC_OPTS='--color --format documentation'" rvm: - - 1.9.3 - 1.8.7 + - 1.9.3 + - 2.0.0 - ruby-head env: - - PUPPET_GEM_VERSION="~> 2.7" - PUPPET_GEM_VERSION=">= 3.0.0" matrix: allow_failures: + - rvm: 2.0.0 - rvm: ruby-head - exclude: - - rvm: 1.9.3 - env: PUPPET_GEM_VERSION="~> 2.7" - - rvm: ruby-head + include: + - rvm: 1.8.7 env: PUPPET_GEM_VERSION="~> 2.7" notifications: email: false @@ -1,5 +1,84 @@ -2012-11-28 - Peter Meier <peter.meier@immerda.ch> - 3.2.0 - * Add reject() function (a79b2cd) +2013-04-12 - Jeff McCune <jeff@puppetlabs.com> - 4.0.2 + * Update user information in gemspec to make the intent of the Gem clear. + +2013-04-11 - Jeff McCune <jeff@puppetlabs.com> - 4.0.1 + * Fix README function documentation (ab3e30c) + +2013-04-11 - Jeff McCune <jeff@puppetlabs.com> - 4.0.0 + * stdlib 4.0 drops support with Puppet 2.7 + * stdlib 4.0 preserves support with Puppet 3 + +2013-04-11 - Jeff McCune <jeff@puppetlabs.com> - 4.0.0 + * Add ability to use puppet from git via bundler (9c5805f) + +2013-04-10 - Jeff McCune <jeff@puppetlabs.com> - 4.0.0 + * (maint) Make stdlib usable as a Ruby GEM (e81a45e) + +2013-04-10 - Erik Dalén <dalen@spotify.com> - 4.0.0 + * Add a count function (f28550e) + +2013-03-31 - Amos Shapira <ashapira@atlassian.com> - 4.0.0 + * (#19998) Implement any2array (7a2fb80) + +2013-03-29 - Steve Huff <shuff@vecna.org> - 4.0.0 + * (19864) num2bool match fix (8d217f0) + +2013-03-20 - Erik Dalén <dalen@spotify.com> - 4.0.0 + * Allow comparisons of Numeric and number as String (ff5dd5d) + +2013-03-26 - Richard Soderberg <rsoderberg@mozilla.com> - 4.0.0 + * add suffix function to accompany the prefix function (88a93ac) + +2013-03-19 - Kristof Willaert <kristof.willaert@gmail.com> - 4.0.0 + * Add floor function implementation and unit tests (0527341) + +2012-04-03 - Eric Shamow <eric@puppetlabs.com> - 4.0.0 + * (#13610) Add is_function_available to stdlib (961dcab) + +2012-12-17 - Justin Lambert <jlambert@eml.cc> - 4.0.0 + * str2bool should return a boolean if called with a boolean (5d5a4d4) + +2012-10-23 - Uwe Stuehler <ustuehler@team.mobile.de> - 4.0.0 + * Fix number of arguments check in flatten() (e80207b) + +2013-03-11 - Jeff McCune <jeff@puppetlabs.com> - 4.0.0 + * Add contributing document (96e19d0) + +2013-03-04 - Raphaël Pinson <raphael.pinson@camptocamp.com> - 4.0.0 + * Add missing documentation for validate_augeas and validate_cmd to README.markdown (a1510a1) + +2013-02-14 - Joshua Hoblitt <jhoblitt@cpan.org> - 4.0.0 + * (#19272) Add has_element() function (95cf3fe) + +2013-02-07 - Raphaël Pinson <raphael.pinson@camptocamp.com> - 4.0.0 + * validate_cmd(): Use Puppet::Util::Execution.execute when available (69248df) + +2012-12-06 - Raphaël Pinson <raphink@gmail.com> - 4.0.0 + * Add validate_augeas function (3a97c23) + +2012-12-06 - Raphaël Pinson <raphink@gmail.com> - 4.0.0 + * Add validate_cmd function (6902cc5) + +2013-01-14 - David Schmitt <david@dasz.at> - 4.0.0 + * Add geppetto project definition (b3fc0a3) + +2013-01-02 - Jaka Hudoklin <jakahudoklin@gmail.com> - 4.0.0 + * Add getparam function to get defined resource parameters (20e0e07) + +2013-01-05 - Jeff McCune <jeff@puppetlabs.com> - 4.0.0 + * (maint) Add Travis CI Support (d082046) + +2012-12-04 - Jeff McCune <jeff@puppetlabs.com> - 4.0.0 + * Clarify that stdlib 3 supports Puppet 3 (3a6085f) + +2012-11-30 - Erik Dalén <dalen@spotify.com> - 4.0.0 + * maint: style guideline fixes (7742e5f) + +2012-11-09 - James Fryman <james@frymanet.com> - 4.0.0 + * puppet-lint cleanup (88acc52) + +2012-11-06 - Joe Julian <me@joejulian.name> - 4.0.0 + * Add function, uriescape, to URI.escape strings. Redmine #17459 (fd52b8d) 2012-09-18 - Chad Metcalf <chad@wibidata.com> - 3.2.0 * Add an ensure_packages function. (8a8c09e) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..bd11f63 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,65 @@ +# How to contribute + +Third-party patches are essential for keeping stdlib great. We simply can't +access the huge number of platforms and myriad configurations for running +stdlib. We want to keep it as easy as possible to contribute changes that +get things working in your environment. There are a few guidelines that we +need contributors to follow so that we can have a chance of keeping on +top of things. + +## Getting Started + +* Make sure you have a [Redmine account](http://projects.puppetlabs.com) +* Make sure you have a [GitHub account](https://github.com/signup/free) +* Submit a ticket for your issue, assuming one does not already exist. + * Clearly describe the issue including steps to reproduce when it is a bug. + * Make sure you fill in the earliest version that you know has the issue. +* Fork the repository on GitHub + +## Making Changes + +* Create a topic branch from where you want to base your work. + * This is usually the master branch. + * Only target release branches if you are certain your fix must be on that + branch. + * To quickly create a topic branch based on master; `git branch + fix/master/my_contribution master` then checkout the new branch with `git + checkout fix/master/my_contribution`. Please avoid working directly on the + `master` branch. +* Make commits of logical units. +* Check for unnecessary whitespace with `git diff --check` before committing. +* Make sure your commit messages are in the proper format. + +```` + (#99999) Make the example in CONTRIBUTING imperative and concrete + + Without this patch applied the example commit message in the CONTRIBUTING + document is not a concrete example. This is a problem because the + contributor is left to imagine what the commit message should look like + based on a description rather than an example. This patch fixes the + problem by making the example concrete and imperative. + + The first line is a real life imperative statement with a ticket number + from our issue tracker. The body describes the behavior without the patch, + why this is a problem, and how the patch fixes the problem when applied. +```` + +* Make sure you have added the necessary tests for your changes. +* Run _all_ the tests to assure nothing else was accidentally broken. + +## Submitting Changes + +* Sign the [Contributor License Agreement](http://links.puppetlabs.com/cla). +* Push your changes to a topic branch in your fork of the repository. +* Submit a pull request to the repository in the puppetlabs organization. +* Update your Redmine ticket to mark that you have submitted code and are ready for it to be reviewed. + * Include a link to the pull request in the ticket + +# Additional Resources + +* [More information on contributing](http://links.puppetlabs.com/contribute-to-puppet) +* [Bug tracker (Redmine)](http://projects.puppetlabs.com) +* [Contributor License Agreement](http://links.puppetlabs.com/cla) +* [General GitHub documentation](http://help.github.com/) +* [GitHub pull request documentation](http://help.github.com/send-pull-requests/) +* #puppet-dev IRC channel on freenode.org @@ -1,4 +1,15 @@ -source :rubygems +source "https://rubygems.org" + +def location_for(place, fake_version = nil) + mdata = /^(git:[^#]*)#(.*)/.match(place) + if mdata + [fake_version, { :git => mdata[1], :branch => mdata[2], :require => false }].compact + elsif place =~ /^file:\/\/(.*)/ + ['>= 0', { :path => File.expand_path(mdata[1]), :require => false }] + else + [place, { :require => false }] + end +end group :development do gem 'watchr' @@ -6,6 +17,7 @@ end group :development, :test do gem 'rake' + gem 'puppetmodule-stdlib', ">= 1.0.0", :path => File.expand_path("..", __FILE__) gem 'rspec', "~> 2.11.0", :require => false gem 'mocha', "~> 0.10.5", :require => false gem 'puppetlabs_spec_helper', :require => false @@ -13,7 +25,7 @@ group :development, :test do end if puppetversion = ENV['PUPPET_GEM_VERSION'] - gem 'puppet', puppetversion, :require => false + gem 'puppet', *location_for(puppetversion) else gem 'puppet', :require => false end @@ -1,6 +1,6 @@ name 'puppetlabs-stdlib' -version '3.2.0' -source 'git://github.com/puppetlabs/puppetlabs-stdlib' +version '4.0.2' +source 'git://github.com/puppetlabs/puppetlabs-stdlib.git' author 'puppetlabs' license 'Apache 2.0' summary 'Puppet Module Standard Library' diff --git a/README.markdown b/README.markdown index c58d31f..0efaf16 100644 --- a/README.markdown +++ b/README.markdown @@ -28,9 +28,11 @@ older versions of Puppet Enterprise that Puppet Labs still supports will have bugfix maintenance branches periodically "merged up" into master. The current list of integration branches are: - * v2.1.x (v2.1.1 released in PE 1.2, 1.2.1, 1.2.3, 1.2.4) + * v2.1.x (v2.1.1 released in PE 1) * v2.2.x (Never released as part of PE, only to the Forge) - * v2.3.x (Released in PE 2.5.x) + * v2.3.x (Released in PE 2) + * v3.0.x (Never released as part of PE, only to the Forge) + * v4.0.x (Drops support for Puppet 2.7) * master (mainline development branch) The first Puppet Enterprise version including the stdlib module is Puppet @@ -38,6 +40,12 @@ Enterprise 1.2. # Compatibility # +Puppet Versions | < 2.6 | 2.6 | 2.7 | 3.x | +:---------------|:-----:|:---:|:---:|:----: +**stdlib 2.x** | no | **yes** | **yes** | no +**stdlib 3.x** | no | no | **yes** | **yes** +**stdlib 4.x** | no | no | no | **yes** + The stdlib module does not work with Puppet versions released prior to Puppet 2.6.0. @@ -50,12 +58,27 @@ All stdlib releases in the 2.0 major version support Puppet 2.6 and Puppet 2.7. The 3.0 major release of stdlib drops support for Puppet 2.6. Stdlib 3.x supports Puppet 2 and Puppet 3. +## stdlib 4.x ## + +The 4.0 major release of stdlib drops support for Puppet 2.7. Stdlib 4.x +supports Puppet 3. Notably, ruby 1.8.5 is no longer supported though ruby +1.8.7, 1.9.3, and 2.0.0 are fully supported. + # Functions # abs --- -Returns the absolute value of a number, for example -34.56 becomes 34.56. Takes -a single integer and float value as an argument. +Returns the absolute value of a number, for example -34.56 becomes +34.56. Takes a single integer and float value as an argument. + + +- *Type*: rvalue + +any2array +--------- +This converts any object to an array containing that object. Empty argument +lists are converted to an empty array. Arrays are left untouched. Hashes are +converted to arrays of alternating keys and values. - *Type*: rvalue @@ -80,9 +103,9 @@ Requires either a single string or an array as an input. chomp ----- -Removes the record separator from the end of a string or an array of strings, -for example `hello\n` becomes `hello`. Requires a single string or array as an -input. +Removes the record separator from the end of a string or an array of +strings, for example `hello\n` becomes `hello`. +Requires a single string or array as an input. - *Type*: rvalue @@ -99,8 +122,25 @@ Requires a string or array of strings as input. - *Type*: rvalue concat +------ +Appends the contents of array 2 onto array 1. + +*Example:* + + concat(['1','2','3'],['4','5','6']) + +Would result in: + + ['1','2','3','4','5','6'] + + +- *Type*: rvalue + +count ----- -Appends the contents of the second array onto the first array. +Takes an array as first argument and an optional second argument. +Count the number of elements in array that matches second argument. +If called with only an array it counts the number of elements that are not nil/undef. - *Type*: rvalue @@ -125,13 +165,19 @@ to the catalog, and false otherwise. delete ------ -Deletes a selected element from an array. +Deletes all instances of a given element from an array, substring from a +string, or key from a hash. *Examples:* - delete(['a','b','c'], 'b') + delete(['a','b','c','b'], 'b') + Would return: ['a','c'] -Would return: ['a','c'] + delete({'a'=>1,'b'=>2,'c'=>3}, 'b') + Would return: {'a'=>1,'c'=>3} + + delete('abracadabra', 'bra') + Would return: 'acada' - *Type*: rvalue @@ -163,6 +209,13 @@ Returns true if the variable is empty. - *Type*: rvalue +ensure_packages +--------------- +Takes a list of packages and only installs them if they don't already exist. + + +- *Type*: statement + ensure_resource --------------- Takes a resource type, title, and a list of attributes that describe a @@ -198,6 +251,14 @@ Would return: ['a','b','c'] - *Type*: rvalue +floor +----- +Returns the largest integer less or equal to the argument. +Takes a single numeric value as an argument. + + +- *Type*: rvalue + fqdn_rotate ----------- Rotates an array a random number of times based on a nodes fqdn. @@ -218,11 +279,10 @@ Example: getparam -------- +Takes a resource reference and name of the parameter and +returns value of resource's parameter. -Takes a resource reference and name of the parameter and returns -value of resource's parameter. - -For example: +*Examples:* define example_resource($param) { } @@ -233,6 +293,9 @@ For example: getparam(Example_resource["example_resource_instance"], "param") +Would return: param_value + + - *Type*: rvalue getvar @@ -269,6 +332,44 @@ Would return: - *Type*: rvalue +has_interface_with +------------------ +Returns boolean based on kind and value: +* macaddress +* netmask +* ipaddress +* network + +has_interface_with("macaddress", "x:x:x:x:x:x") +has_interface_with("ipaddress", "127.0.0.1") => true +etc. + +If no "kind" is given, then the presence of the interface is checked: +has_interface_with("lo") => true + + +- *Type*: rvalue + +has_ip_address +-------------- +Returns true if the client has the requested IP address on some interface. + +This function iterates through the 'interfaces' fact and checks the +'ipaddress_IFACE' facts, performing a simple string comparison. + + +- *Type*: rvalue + +has_ip_network +-------------- +Returns true if the client has an IP address within the requested network. + +This function iterates through the 'interfaces' fact and checks the +'network_IFACE' facts, performing a simple string comparision. + + +- *Type*: rvalue + has_key ------- Determine if a hash has a certain key value. @@ -304,20 +405,25 @@ is_array -------- Returns true if the variable passed to this function is an array. - - *Type*: rvalue is_domain_name -------------- Returns true if the string passed to this function is a syntactically correct domain name. - - *Type*: rvalue is_float -------- Returns true if the variable passed to this function is a float. +- *Type*: rvalue + +is_function_available +--------------------- +This function accepts a string as an argument, determines whether the +Puppet runtime has access to a function by that name. It returns a +true if the function exists, false if not. - *Type*: rvalue @@ -325,42 +431,36 @@ is_hash ------- Returns true if the variable passed to this function is a hash. - - *Type*: rvalue is_integer ---------- Returns true if the variable returned to this string is an integer. - - *Type*: rvalue is_ip_address ------------- Returns true if the string passed to this function is a valid IP address. - - *Type*: rvalue is_mac_address -------------- Returns true if the string passed to this function is a valid mac address. - - *Type*: rvalue is_numeric ---------- Returns true if the variable passed to this function is a number. - - *Type*: rvalue is_string --------- Returns true if the variable passed to this function is a string. - - *Type*: rvalue join @@ -373,6 +473,19 @@ This function joins an array into a string using a seperator. Would result in: "a,b,c" +- *Type*: rvalue + +join_keys_to_values +------------------- +This function joins each key of a hash to that key's corresponding value with a +separator. Keys and values are cast to strings. The return value is an array in +which each element is one joined key/value pair. + +*Examples:* + + join_keys_to_values({'a'=>1,'b'=>2}, " is ") + +Would result in: ["a is 1","b is 2"] - *Type*: rvalue @@ -380,7 +493,6 @@ keys ---- Returns the keys of a hash as an array. - - *Type*: rvalue loadyaml @@ -399,6 +511,12 @@ lstrip ------ Strips leading spaces to the left of a string. +- *Type*: rvalue + +max +--- +Returns the highest value of all arguments. +Requires at least one argument. - *Type*: rvalue @@ -416,7 +534,6 @@ Would return: true Would return: false - - *Type*: rvalue merge @@ -433,15 +550,20 @@ For example: When there is a duplicate key, the key in the rightmost hash will "win." +- *Type*: rvalue +min +--- +Returns the lowest value of all arguments. +Requires at least one argument. - *Type*: rvalue num2bool -------- -This function converts a number into a true boolean. Zero becomes false. Numbers -higher then 0 become true. - +This function converts a number or a string representation of a number into a +true boolean. Zero or anything non-numeric becomes false. Numbers higher then 0 +become true. - *Type*: rvalue @@ -450,7 +572,6 @@ parsejson This function accepts JSON as a string and converts into the correct Puppet structure. - - *Type*: rvalue parseyaml @@ -458,6 +579,22 @@ parseyaml This function accepts YAML as a string and converts it into the correct Puppet structure. +- *Type*: rvalue + +pick +---- +This function is similar to a coalesce function in SQL in that it will return +the first value in a list of values that is not undefined or an empty string +(two things in Puppet that will return a boolean false value). Typically, +this function is used to check for a value in the Puppet Dashboard/Enterprise +Console, and failover to a default value like the following: + + $real_jenkins_version = pick($::jenkins_version, '1.449') + +The value of $real_jenkins_version will first look for a top-scope variable +called 'jenkins_version' (note that parameters set in the Puppet Dashboard/ +Enterprise Console are brought into Puppet as top-scope variables), and, +failing that, will use a default value of 1.449. - *Type*: rvalue @@ -465,13 +602,12 @@ prefix ------ This function applies a prefix to all elements in an array. -*Examles:* +*Examples:* prefix(['a','b','c'], 'p') Will return: ['pa','pb','pc'] - - *Type*: rvalue range @@ -498,6 +634,21 @@ Will return: ["a","b","c"] Will return: ["host01", "host02", ..., "host09", "host10"] +- *Type*: rvalue + +reject +------ +This function searches through an array and rejects all elements that match +the provided regular expression. + +*Examples:* + + reject(['aaa','bbb','ccc','aaaddd'], 'aaa') + +Would return: + + ['bbb','ccc'] + - *Type*: rvalue @@ -505,35 +656,30 @@ reverse ------- Reverses the order of a string or array. - - *Type*: rvalue rstrip ------ Strips leading spaces to the right of the string. - - *Type*: rvalue shuffle ------- Randomizes the order of a string or array elements. - - *Type*: rvalue size ---- Returns the number of elements in a string or array. - - *Type*: rvalue sort ---- Sorts strings and arrays lexically. - - *Type*: rvalue squeeze @@ -541,7 +687,6 @@ squeeze Returns a new string where runs of the same character that occur in this set are replaced by a single character. - - *Type*: rvalue str2bool @@ -555,10 +700,10 @@ like: 0, f, n, false, no to 'false'. str2saltedsha512 ---------------- -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. +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. - *Type*: rvalue @@ -647,6 +792,19 @@ Would result in: "aaa" - *Type*: rvalue +suffix +------ +This function applies a suffix to all elements in an array. + +*Examples:* + + suffix(['a','b','c'], 'p') + +Will return: ['ap','bp','cp'] + + +- *Type*: rvalue + swapcase -------- This function will swap the existing case of a string. @@ -728,7 +886,15 @@ Converts a string or an array of strings to uppercase. Will return: - ABCD + ASDF + + +- *Type*: rvalue + +uriescape +--------- +Urlencodes a string or array of strings. +Requires either a single string or an array as an input. - *Type*: rvalue @@ -779,6 +945,39 @@ The following values will fail, causing compilation to abort: - *Type*: statement +validate_augeas +--------------- +Perform validation of a string using an Augeas lens +The first argument of this function should be a string to +test, and the second argument should be the name of the Augeas lens to use. +If Augeas fails to parse the string with the lens, the compilation will +abort with a parse error. + +A third argument can be specified, listing paths which should +not be found in the file. The `$file` variable points to the location +of the temporary file being tested in the Augeas tree. + +For example, if you want to make sure your passwd content never contains +a user `foo`, you could write: + + validate_augeas($passwdcontent, 'Passwd.lns', ['$file/foo']) + +Or if you wanted to ensure that no users used the '/bin/barsh' shell, +you could use: + + validate_augeas($passwdcontent, 'Passwd.lns', ['$file/*[shell="/bin/barsh"]'] + +If a fourth argument is specified, this will be the error message raised and +seen by the user. + +A helpful error message can be returned like this: + + validate_augeas($sudoerscontent, 'Sudoers.lns', [], 'Failed to validate sudoers content with Augeas') + + + +- *Type*: statement + validate_bool ------------- Validate that all passed values are either true or false. Abort catalog @@ -801,6 +1000,28 @@ The following values will fail, causing compilation to abort: - *Type*: statement +validate_cmd +------------ +Perform validation of a string with an external command. +The first argument of this function should be a string to +test, and the second argument should be a path to a test command +taking a file as last argument. If the command, launched against +a tempfile containing the passed string, returns a non-null value, +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. + +A helpful error message can be returned like this: + +Example: + + validate_cmd($sudoerscontent, '/usr/sbin/visudo -c -f', 'Visudo failed to validate sudoers content') + + + +- *Type*: statement + validate_hash ------------- Validate that all passed values are hash data structures. Abort catalog @@ -890,7 +1111,6 @@ The following values will fail, causing compilation to abort: validate_string($undefined) - - *Type*: statement values @@ -955,3 +1175,5 @@ Would result in: - *Type*: rvalue + +*This page autogenerated on 2013-04-11 13:54:25 -0700* diff --git a/README_SPECS.markdown b/README_SPECS.markdown new file mode 100644 index 0000000..917b631 --- /dev/null +++ b/README_SPECS.markdown @@ -0,0 +1,7 @@ +NOTE +==== + +This project's specs depend on puppet core, and thus they require the +`puppetlabs_spec_helper` project. For more information please see the README +in that project, which can be found here: [puppetlabs spec +helper](https://github.com/puppetlabs/puppetlabs_spec_helper) diff --git a/lib/puppet/parser/functions/any2array.rb b/lib/puppet/parser/functions/any2array.rb new file mode 100644 index 0000000..e71407e --- /dev/null +++ b/lib/puppet/parser/functions/any2array.rb @@ -0,0 +1,33 @@ +# +# any2array.rb +# + +module Puppet::Parser::Functions + newfunction(:any2array, :type => :rvalue, :doc => <<-EOS +This converts any object to an array containing that object. Empty argument +lists are converted to an empty array. Arrays are left untouched. Hashes are +converted to arrays of alternating keys and values. + EOS + ) do |arguments| + + if arguments.empty? + return [] + end + + if arguments.length == 1 + if arguments[0].kind_of?(Array) + return arguments[0] + elsif arguments[0].kind_of?(Hash) + result = [] + arguments[0].each do |key, value| + result << key << value + end + return result + end + end + + return arguments + end +end + +# vim: set ts=2 sw=2 et : diff --git a/lib/puppet/parser/functions/count.rb b/lib/puppet/parser/functions/count.rb new file mode 100644 index 0000000..52de1b8 --- /dev/null +++ b/lib/puppet/parser/functions/count.rb @@ -0,0 +1,22 @@ +module Puppet::Parser::Functions + newfunction(:count, :type => :rvalue, :arity => -2, :doc => <<-EOS +Takes an array as first argument and an optional second argument. +Count the number of elements in array that matches second argument. +If called with only an array it counts the number of elements that are not nil/undef. + EOS + ) do |args| + + if (args.size > 2) then + raise(ArgumentError, "count(): Wrong number of arguments "+ + "given #{args.size} for 1 or 2.") + end + + collection, item = args + + if item then + collection.count item + else + collection.count { |obj| obj != nil && obj != :undef && obj != '' } + end + end +end diff --git a/lib/puppet/parser/functions/flatten.rb b/lib/puppet/parser/functions/flatten.rb index 781da78..a1ed183 100644 --- a/lib/puppet/parser/functions/flatten.rb +++ b/lib/puppet/parser/functions/flatten.rb @@ -16,7 +16,7 @@ Would return: ['a','b','c'] ) do |arguments| raise(Puppet::ParseError, "flatten(): Wrong number of arguments " + - "given (#{arguments.size} for 1)") if arguments.size < 1 + "given (#{arguments.size} for 1)") if arguments.size != 1 array = arguments[0] diff --git a/lib/puppet/parser/functions/floor.rb b/lib/puppet/parser/functions/floor.rb new file mode 100644 index 0000000..a401923 --- /dev/null +++ b/lib/puppet/parser/functions/floor.rb @@ -0,0 +1,20 @@ +module Puppet::Parser::Functions + newfunction(:floor, :type => :rvalue, :doc => <<-EOS + Returns the largest integer less or equal to the argument. + Takes a single numeric value as an argument. + EOS + ) do |arguments| + + raise(Puppet::ParseError, "floor(): Wrong number of arguments " + + "given (#{arguments.size} for 1)") if arguments.size != 1 + + arg = arguments[0] + + raise(Puppet::ParseError, "floor(): Wrong argument type " + + "given (#{arg.class} for Numeric)") if arg.is_a?(Numeric) == false + + arg.floor + end +end + +# vim: set ts=2 sw=2 et : diff --git a/lib/puppet/parser/functions/is_function_available.rb b/lib/puppet/parser/functions/is_function_available.rb new file mode 100644 index 0000000..6cbd35c --- /dev/null +++ b/lib/puppet/parser/functions/is_function_available.rb @@ -0,0 +1,23 @@ +# +# is_function_available.rb +# + +module Puppet::Parser::Functions + newfunction(:is_function_available, :type => :rvalue, :doc => <<-EOS +This function accepts a string as an argument, determines whether the +Puppet runtime has access to a function by that name. It returns a +true if the function exists, false if not. + EOS + ) do |arguments| + + if (arguments.size != 1) then + raise(Puppet::ParseError, "is_function_available?(): Wrong number of arguments "+ + "given #{arguments.size} for 1") + end + + function = Puppet::Parser::Functions.function(arguments[0].to_sym) + function.is_a?(String) and not function.empty? + end +end + +# vim: set ts=2 sw=2 et : diff --git a/lib/puppet/parser/functions/max.rb b/lib/puppet/parser/functions/max.rb index 10b6f74..60fb94a 100644 --- a/lib/puppet/parser/functions/max.rb +++ b/lib/puppet/parser/functions/max.rb @@ -8,6 +8,14 @@ module Puppet::Parser::Functions raise(Puppet::ParseError, "max(): Wrong number of arguments " + "need at least one") if args.size == 0 - return args.max + # Sometimes we get numbers as numerics and sometimes as strings. + # We try to compare them as numbers when possible + return args.max do |a,b| + if a.to_s =~ /\A-?\d+(.\d+)?\z/ and b.to_s =~ /\A-?\d+(.\d+)?\z/ then + a.to_f <=> b.to_f + else + a.to_s <=> b.to_s + end + end end end diff --git a/lib/puppet/parser/functions/min.rb b/lib/puppet/parser/functions/min.rb index abf1b62..6bd6ebf 100644 --- a/lib/puppet/parser/functions/min.rb +++ b/lib/puppet/parser/functions/min.rb @@ -8,6 +8,14 @@ module Puppet::Parser::Functions raise(Puppet::ParseError, "min(): Wrong number of arguments " + "need at least one") if args.size == 0 - return args.min + # Sometimes we get numbers as numerics and sometimes as strings. + # We try to compare them as numbers when possible + return args.min do |a,b| + if a.to_s =~ /\A^-?\d+(.\d+)?\z/ and b.to_s =~ /\A-?\d+(.\d+)?\z/ then + a.to_f <=> b.to_f + else + a.to_s <=> b.to_s + end + end end end diff --git a/lib/puppet/parser/functions/num2bool.rb b/lib/puppet/parser/functions/num2bool.rb index 874db22..af0e6ed 100644 --- a/lib/puppet/parser/functions/num2bool.rb +++ b/lib/puppet/parser/functions/num2bool.rb @@ -2,38 +2,41 @@ # num2bool.rb # -# TODO(Krzysztof Wilczynski): We probably need to approach numeric values differently ... - module Puppet::Parser::Functions newfunction(:num2bool, :type => :rvalue, :doc => <<-EOS -This function converts a number into a true boolean. Zero becomes false. Numbers -higher then 0 become true. +This function converts a number or a string representation of a number into a +true boolean. Zero or anything non-numeric becomes false. Numbers higher then 0 +become true. EOS ) do |arguments| raise(Puppet::ParseError, "num2bool(): Wrong number of arguments " + - "given (#{arguments.size} for 1)") if arguments.size < 1 + "given (#{arguments.size} for 1)") if arguments.size != 1 number = arguments[0] - # Only numbers allowed ... - unless number.match(/^\-?\d+$/) - raise(Puppet::ParseError, 'num2bool(): Requires integer to work with') + case number + when Numeric + # Yay, it's a number + when String + begin + number = Float(number) + rescue ArgumentError => ex + raise(Puppet::ParseError, "num2bool(): '#{number}' does not look like a number: #{ex.message}") + end + else + begin + number = number.to_s + rescue NoMethodError => ex + raise(Puppet::ParseError, "num2bool(): Unable to parse argument: #{ex.message}") + end end - result = case number - when /^0$/ - false - when /^\-?\d+$/ - # Numbers in Puppet are often string-encoded which is troublesome ... - number = number.to_i - # We yield true for any positive number and false otherwise ... - number > 0 ? true : false - else - raise(Puppet::ParseError, 'num2bool(): Unknown numeric format given') - end + # Truncate Floats + number = number.to_i - return result + # Return true for any positive number and false otherwise + return number > 0 end end diff --git a/lib/puppet/parser/functions/prefix.rb b/lib/puppet/parser/functions/prefix.rb index 4593976..62211ae 100644 --- a/lib/puppet/parser/functions/prefix.rb +++ b/lib/puppet/parser/functions/prefix.rb @@ -6,7 +6,7 @@ module Puppet::Parser::Functions newfunction(:prefix, :type => :rvalue, :doc => <<-EOS This function applies a prefix to all elements in an array. -*Examles:* +*Examples:* prefix(['a','b','c'], 'p') @@ -21,14 +21,14 @@ Will return: ['pa','pb','pc'] array = arguments[0] unless array.is_a?(Array) - raise(Puppet::ParseError, 'prefix(): Requires array to work with') + raise Puppet::ParseError, "prefix(): expected first argument to be an Array, got #{array.inspect}" end prefix = arguments[1] if arguments[1] if prefix unless prefix.is_a?(String) - raise(Puppet::ParseError, 'prefix(): Requires string to work with') + raise Puppet::ParseError, "prefix(): expected second argument to be a String, got #{suffix.inspect}" end end diff --git a/lib/puppet/parser/functions/str2bool.rb b/lib/puppet/parser/functions/str2bool.rb index 0509c2b..fece7a6 100644 --- a/lib/puppet/parser/functions/str2bool.rb +++ b/lib/puppet/parser/functions/str2bool.rb @@ -14,6 +14,11 @@ like: 0, f, n, false, no to 'false'. "given (#{arguments.size} for 1)") if arguments.size < 1 string = arguments[0] + + # If string is already Boolean, return it + if !!string == string + return string + end unless string.is_a?(String) raise(Puppet::ParseError, 'str2bool(): Requires either ' + diff --git a/lib/puppet/parser/functions/suffix.rb b/lib/puppet/parser/functions/suffix.rb new file mode 100644 index 0000000..f7792d6 --- /dev/null +++ b/lib/puppet/parser/functions/suffix.rb @@ -0,0 +1,45 @@ +# +# suffix.rb +# + +module Puppet::Parser::Functions + newfunction(:suffix, :type => :rvalue, :doc => <<-EOS +This function applies a suffix to all elements in an array. + +*Examples:* + + suffix(['a','b','c'], 'p') + +Will return: ['ap','bp','cp'] + EOS + ) do |arguments| + + # Technically we support two arguments but only first is mandatory ... + raise(Puppet::ParseError, "suffix(): Wrong number of arguments " + + "given (#{arguments.size} for 1)") if arguments.size < 1 + + array = arguments[0] + + unless array.is_a?(Array) + raise Puppet::ParseError, "suffix(): expected first argument to be an Array, got #{array.inspect}" + end + + suffix = arguments[1] if arguments[1] + + if suffix + unless suffix.is_a? String + raise Puppet::ParseError, "suffix(): expected second argument to be a String, got #{suffix.inspect}" + end + end + + # Turn everything into string same as join would do ... + result = array.collect do |i| + i = i.to_s + suffix ? i + suffix : i + end + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/lib/puppet/type/anchor.rb b/lib/puppet/type/anchor.rb index 6b81732..fe1e5aa 100644 --- a/lib/puppet/type/anchor.rb +++ b/lib/puppet/type/anchor.rb @@ -38,4 +38,9 @@ Puppet::Type.newtype(:anchor) do desc "The name of the anchor resource." end + def refresh + # We don't do anything with them, but we need this to + # show that we are "refresh aware" and not break the + # chain of propagation. + end end diff --git a/spec/classes/anchor_spec.rb b/spec/classes/anchor_spec.rb new file mode 100644 index 0000000..2dd17de --- /dev/null +++ b/spec/classes/anchor_spec.rb @@ -0,0 +1,32 @@ +require 'puppet' +require 'rspec-puppet' + +describe "anchorrefresh" do + let(:node) { 'testhost.example.com' } + let :pre_condition do + <<-ANCHORCLASS +class anchored { + anchor { 'anchored::begin': } + ~> anchor { 'anchored::end': } +} + +class anchorrefresh { + notify { 'first': } + ~> class { 'anchored': } + ~> anchor { 'final': } +} + ANCHORCLASS + end + + def apply_catalog_and_return_exec_rsrc + catalog = subject.to_ral + transaction = catalog.apply + transaction.resource_status("Anchor[final]") + end + + it 'propagates events through the anchored class' do + resource = apply_catalog_and_return_exec_rsrc + + expect(resource.restarted).to eq(true) + end +end diff --git a/spec/unit/puppet/parser/functions/any2array_spec.rb b/spec/unit/puppet/parser/functions/any2array_spec.rb new file mode 100644 index 0000000..b266e84 --- /dev/null +++ b/spec/unit/puppet/parser/functions/any2array_spec.rb @@ -0,0 +1,55 @@ +#! /usr/bin/env ruby -S rspec +require 'spec_helper' + +describe "the any2array function" do + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + it "should exist" do + Puppet::Parser::Functions.function("any2array").should == "function_any2array" + end + + it "should return an empty array if there is less than 1 argument" do + result = scope.function_any2array([]) + result.should(eq([])) + end + + it "should convert boolean true to [ true ] " do + result = scope.function_any2array([true]) + result.should(eq([true])) + end + + it "should convert one object to [object]" do + result = scope.function_any2array(['one']) + result.should(eq(['one'])) + end + + it "should convert multiple objects to [objects]" do + result = scope.function_any2array(['one', 'two']) + result.should(eq(['one', 'two'])) + end + + it "should return empty array it was called with" do + result = scope.function_any2array([[]]) + result.should(eq([])) + end + + it "should return one-member array it was called with" do + result = scope.function_any2array([['string']]) + result.should(eq(['string'])) + end + + it "should return multi-member array it was called with" do + result = scope.function_any2array([['one', 'two']]) + result.should(eq(['one', 'two'])) + end + + it "should return members of a hash it was called with" do + result = scope.function_any2array([{ 'key' => 'value' }]) + result.should(eq(['key', 'value'])) + end + + it "should return an empty array if it was called with an empty hash" do + result = scope.function_any2array([{ }]) + result.should(eq([])) + end +end diff --git a/spec/unit/puppet/parser/functions/count_spec.rb b/spec/unit/puppet/parser/functions/count_spec.rb new file mode 100644 index 0000000..2453815 --- /dev/null +++ b/spec/unit/puppet/parser/functions/count_spec.rb @@ -0,0 +1,31 @@ +#! /usr/bin/env ruby -S rspec + +require 'spec_helper' + +describe "the count function" do + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + it "should exist" do + Puppet::Parser::Functions.function("count").should == "function_count" + end + + it "should raise a ArgumentError if there is more than 2 arguments" do + lambda { scope.function_count(['foo', 'bar', 'baz']) }.should( raise_error(ArgumentError)) + end + + it "should be able to count arrays" do + scope.function_count([["1","2","3"]]).should(eq(3)) + end + + it "should be able to count matching elements in arrays" do + scope.function_count([["1", "2", "2"], "2"]).should(eq(2)) + end + + it "should not count nil or empty strings" do + scope.function_count([["foo","bar",nil,""]]).should(eq(2)) + end + + it 'does not count an undefined hash key or an out of bound array index (which are both :undef)' do + expect(scope.function_count([["foo",:undef,:undef]])).to eq(1) + end +end diff --git a/spec/unit/puppet/parser/functions/flatten_spec.rb b/spec/unit/puppet/parser/functions/flatten_spec.rb index d4dfd20..dba7a6b 100755 --- a/spec/unit/puppet/parser/functions/flatten_spec.rb +++ b/spec/unit/puppet/parser/functions/flatten_spec.rb @@ -11,6 +11,10 @@ describe "the flatten function" do lambda { scope.function_flatten([]) }.should( raise_error(Puppet::ParseError)) end + it "should raise a ParseError if there is more than 1 argument" do + lambda { scope.function_flatten([[], []]) }.should( raise_error(Puppet::ParseError)) + end + it "should flatten a complex data structure" do result = scope.function_flatten([["a","b",["c",["d","e"],"f","g"]]]) result.should(eq(["a","b","c","d","e","f","g"])) diff --git a/spec/unit/puppet/parser/functions/floor_spec.rb b/spec/unit/puppet/parser/functions/floor_spec.rb new file mode 100644 index 0000000..dbc8c77 --- /dev/null +++ b/spec/unit/puppet/parser/functions/floor_spec.rb @@ -0,0 +1,39 @@ +#! /usr/bin/env ruby -S rspec + +require 'spec_helper' + +describe "the floor function" do + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + it "should exist" do + Puppet::Parser::Functions.function("floor").should == "function_floor" + end + + it "should raise a ParseError if there is less than 1 argument" do + lambda { scope.function_floor([]) }.should( raise_error(Puppet::ParseError, /Wrong number of arguments/)) + end + + it "should should raise a ParseError if input isn't numeric (eg. String)" do + lambda { scope.function_floor(["foo"]) }.should( raise_error(Puppet::ParseError, /Wrong argument type/)) + end + + it "should should raise a ParseError if input isn't numeric (eg. Boolean)" do + lambda { scope.function_floor([true]) }.should( raise_error(Puppet::ParseError, /Wrong argument type/)) + end + + it "should return an integer when a numeric type is passed" do + result = scope.function_floor([12.4]) + result.is_a?(Integer).should(eq(true)) + end + + it "should return the input when an integer is passed" do + result = scope.function_floor([7]) + result.should(eq(7)) + end + + it "should return the largest integer less than or equal to the input" do + result = scope.function_floor([3.8]) + result.should(eq(3)) + end +end + diff --git a/spec/unit/puppet/parser/functions/is_function_available.rb b/spec/unit/puppet/parser/functions/is_function_available.rb new file mode 100644 index 0000000..bd40c51 --- /dev/null +++ b/spec/unit/puppet/parser/functions/is_function_available.rb @@ -0,0 +1,31 @@ +#!/usr/bin/env rspec +require 'spec_helper' + +describe "the is_function_available 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("is_function_available").should == "function_is_function_available" + end + + it "should raise a ParseError if there is less than 1 arguments" do + lambda { @scope.function_is_function_available([]) }.should( raise_error(Puppet::ParseError)) + end + + it "should return false if a nonexistent function is passed" do + result = @scope.function_is_function_available(['jeff_mccunes_left_sock']) + result.should(eq(false)) + end + + it "should return true if an available function is passed" do + result = @scope.function_is_function_available(['require']) + result.should(eq(true)) + end + +end diff --git a/spec/unit/puppet/parser/functions/max_spec.rb b/spec/unit/puppet/parser/functions/max_spec.rb index 604927e..ff6f2b3 100755 --- a/spec/unit/puppet/parser/functions/max_spec.rb +++ b/spec/unit/puppet/parser/functions/max_spec.rb @@ -20,4 +20,8 @@ describe "the max function" do it "should be able to compare numbers" do scope.function_max([6,8,4]).should(eq(8)) end + + it "should be able to compare a number with a stringified number" do + scope.function_max([1,"2"]).should(eq("2")) + end end diff --git a/spec/unit/puppet/parser/functions/min_spec.rb b/spec/unit/puppet/parser/functions/min_spec.rb index 781422c..71d593e 100755 --- a/spec/unit/puppet/parser/functions/min_spec.rb +++ b/spec/unit/puppet/parser/functions/min_spec.rb @@ -20,4 +20,8 @@ describe "the min function" do it "should be able to compare numbers" do scope.function_min([6,8,4]).should(eq(4)) end + + it "should be able to compare a number with a stringified number" do + scope.function_min([1,"2"]).should(eq(1)) + end end diff --git a/spec/unit/puppet/parser/functions/num2bool_spec.rb b/spec/unit/puppet/parser/functions/num2bool_spec.rb index 640c689..b56196d 100644 --- a/spec/unit/puppet/parser/functions/num2bool_spec.rb +++ b/spec/unit/puppet/parser/functions/num2bool_spec.rb @@ -8,17 +8,60 @@ describe "the num2bool function" do Puppet::Parser::Functions.function("num2bool").should == "function_num2bool" end - it "should raise a ParseError if there is less than 1 arguments" do + it "should raise a ParseError if there are no arguments" do lambda { scope.function_num2bool([]) }.should( raise_error(Puppet::ParseError)) end - it "should return true if 1" do + it "should raise a ParseError if there are more than 1 arguments" do + lambda { scope.function_num2bool(["foo","bar"]) }.should( raise_error(Puppet::ParseError)) + end + + it "should raise a ParseError if passed something non-numeric" do + lambda { scope.function_num2bool(["xyzzy"]) }.should( raise_error(Puppet::ParseError)) + end + + it "should return true if passed string 1" do result = scope.function_num2bool(["1"]) result.should(be_true) end - it "should return false if 0" do + it "should return true if passed string 1.5" do + result = scope.function_num2bool(["1.5"]) + result.should(be_true) + end + + it "should return true if passed number 1" do + result = scope.function_num2bool([1]) + result.should(be_true) + end + + it "should return false if passed string 0" do result = scope.function_num2bool(["0"]) result.should(be_false) end + + it "should return false if passed number 0" do + result = scope.function_num2bool([0]) + result.should(be_false) + end + + it "should return false if passed string -1" do + result = scope.function_num2bool(["-1"]) + result.should(be_false) + end + + it "should return false if passed string -1.5" do + result = scope.function_num2bool(["-1.5"]) + result.should(be_false) + end + + it "should return false if passed number -1" do + result = scope.function_num2bool([-1]) + result.should(be_false) + end + + it "should return false if passed float -1.5" do + result = scope.function_num2bool([-1.5]) + result.should(be_false) + end end diff --git a/spec/unit/puppet/parser/functions/str2bool_spec.rb b/spec/unit/puppet/parser/functions/str2bool_spec.rb index 2782bbe..ef6350f 100644 --- a/spec/unit/puppet/parser/functions/str2bool_spec.rb +++ b/spec/unit/puppet/parser/functions/str2bool_spec.rb @@ -21,4 +21,11 @@ describe "the str2bool function" do result = scope.function_str2bool(["undef"]) result.should(eq(false)) end + + it "should return the boolean it was called with" do + result = scope.function_str2bool([true]) + result.should(eq(true)) + result = scope.function_str2bool([false]) + result.should(eq(false)) + end end diff --git a/spec/unit/puppet/parser/functions/suffix_spec.rb b/spec/unit/puppet/parser/functions/suffix_spec.rb new file mode 100644 index 0000000..c28f719 --- /dev/null +++ b/spec/unit/puppet/parser/functions/suffix_spec.rb @@ -0,0 +1,19 @@ +#! /usr/bin/env ruby -S rspec +require 'spec_helper' + +describe "the suffix function" do + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + it "should exist" do + Puppet::Parser::Functions.function("suffix").should == "function_suffix" + end + + it "should raise a ParseError if there is less than 1 arguments" do + lambda { scope.function_suffix([]) }.should( raise_error(Puppet::ParseError)) + end + + it "should return a suffixed array" do + result = scope.function_suffix([['a','b','c'], 'p']) + result.should(eq(['ap','bp','cp'])) + end +end |