diff options
74 files changed, 2204 insertions, 137 deletions
diff --git a/.gemfile b/.gemfile deleted file mode 100644 index 9aad840..0000000 --- a/.gemfile +++ /dev/null @@ -1,5 +0,0 @@ -source :rubygems - -puppetversion = ENV.key?('PUPPET_VERSION') ? "= #{ENV['PUPPET_VERSION']}" : ['>= 2.7'] -gem 'puppet', puppetversion -gem 'puppetlabs_spec_helper', '>= 0.1.0' 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,3 +2,7 @@ pkg/ .DS_Store metadata.json coverage/ +spec/fixtures/ +Gemfile.lock +.bundle/ +vendor/bundle/ diff --git a/.project b/.project new file mode 100644 index 0000000..4e2c033 --- /dev/null +++ b/.project @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>stdlib</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.cloudsmith.geppetto.pp.dsl.ui.modulefileBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.xtext.ui.shared.xtextBuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.cloudsmith.geppetto.pp.dsl.ui.puppetNature</nature> + <nature>org.eclipse.xtext.ui.shared.xtextNature</nature> + </natures> +</projectDescription> diff --git a/.travis.yml b/.travis.yml index 0ec5a08..1bb1889 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,16 +1,25 @@ language: ruby +bundler_args: --without development +script: "bundle exec rake spec SPEC_OPTS='--color --format documentation'" rvm: - 1.8.7 -before_script: -after_script: -script: "rake spec_full" -branches: - only: - - master + - 1.9.3 + - 2.0.0 + - ruby-head env: - - PUPPET_VERSION=2.7.13 - - PUPPET_VERSION=2.7.6 - - PUPPET_VERSION=2.6.9 + - PUPPET_GEM_VERSION=">= 3.0.0" +matrix: + allow_failures: + - rvm: 2.0.0 + - rvm: ruby-head + include: + - rvm: 1.8.7 + env: PUPPET_GEM_VERSION="~> 2.7" notifications: email: false -gemfile: .gemfile + webhooks: + urls: + - https://puppet-dev-community.herokuapp.com/event/travis-ci/ + on_success: always + on_failure: always + on_start: yes @@ -1,5 +1,106 @@ -2012-11-28 - Peter Meier <peter.meier@immerda.ch> - 3.2.0 - * Add reject() function (a79b2cd) +2013-05-06 - Jeff McCune <jeff@puppetlabs.com> - 4.1.0 + * (#20582) Restore facter_dot_d to stdlib for PE users (3b887c8) + * (maint) Update Gemfile with GEM_FACTER_VERSION (f44d535) + +2013-05-06 - Alex Cline <acline@us.ibm.com> - 4.1.0 + * Terser method of string to array conversion courtesy of ethooz. (d38bce0) + +2013-05-06 - Alex Cline <acline@us.ibm.com> 4.1.0 + * Refactor ensure_resource expectations (b33cc24) + +2013-05-06 - Alex Cline <acline@us.ibm.com> 4.1.0 + * Changed str-to-array conversion and removed abbreviation. (de253db) + +2013-05-03 - Alex Cline <acline@us.ibm.com> 4.1.0 + * (#20548) Allow an array of resource titles to be passed into the ensure_resource function (e08734a) + +2013-05-02 - Raphaël Pinson <raphael.pinson@camptocamp.com> - 4.1.0 + * Add a dirname function (2ba9e47) + +2013-04-29 - Mark Smith-Guerrero <msmithgu@gmail.com> - 4.1.0 + * (maint) Fix a small typo in hash() description (928036a) + +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 @@ -0,0 +1,42 @@ +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' +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 + gem 'rspec-puppet', :require => false +end + +facterversion = ENV['GEM_FACTER_VERSION'] +if facterversion + gem 'facter', *location_for(facterversion) +else + gem 'facter', :require => false +end + +ENV['GEM_PUPPET_VERSION'] ||= ENV['PUPPET_GEM_VERSION'] +puppetversion = ENV['GEM_PUPPET_VERSION'] +if puppetversion + gem 'puppet', *location_for(puppetversion) +else + gem 'puppet', :require => false +end + +# vim:ft=ruby @@ -1,6 +1,6 @@ name 'puppetlabs-stdlib' -version '3.2.0' -source 'git://github.com/puppetlabs/puppetlabs-stdlib' +version '4.1.0' +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 a33add3..0e40f51 100644 --- a/README.markdown +++ b/README.markdown @@ -1,5 +1,7 @@ # Puppet Labs Standard Library # +[](https://travis-ci.org/puppetlabs/puppetlabs-stdlib) + This module provides a "standard library" of resources for developing Puppet Modules. This modules will include the following additions to Puppet @@ -26,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 @@ -36,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. @@ -48,12 +58,36 @@ 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 + +base64 +-------- +Converts a string to and from base64 encoding. +Requires an action ['encode','decode'] and either a plain or base64 encoded +string - *Type*: rvalue @@ -78,9 +112,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 @@ -96,6 +130,30 @@ 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 +----- +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 + defined_with_params ------------------- Takes a resource reference and an optional hash of attributes. @@ -116,13 +174,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 @@ -140,6 +204,28 @@ Would return: ['a','c'] - *Type*: rvalue +difference +---------- +This function returns the difference between two arrays. +The returned array is a copy of the original array, removing any items that +also appear in the second array. + +*Examples:* + + difference(["a","b","c"],["b","c","d"]) + +Would return: ["a"] + +dirname +------- +Returns the `dirname` of a path. + +*Examples:* + + dirname('/path/to/a/file.ext') + +Would return: '/path/to/a' + downcase -------- Converts the case of a string or all strings in an array to lower case. @@ -154,6 +240,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 @@ -171,6 +264,11 @@ If the resource already exists but does not match the specified parameters, this function will attempt to recreate the resource leading to a duplicate resource definition error. +An array of resources can also be passed in and each will be created with +the type and parameters specified if it doesn't already exist. + + ensure_resource('user', ['dan','alex'], {'ensure' => 'present'}) + - *Type*: statement @@ -189,6 +287,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. @@ -207,6 +313,27 @@ Example: - *Type*: rvalue +getparam +-------- +Takes a resource reference and name of the parameter and +returns value of resource's parameter. + +*Examples:* + + define example_resource($param) { + } + + example_resource { "example_resource_instance": + param => "param_value" + } + + getparam(Example_resource["example_resource_instance"], "param") + +Would return: param_value + + +- *Type*: rvalue + getvar ------ Lookup a variable in a remote namespace. @@ -241,6 +368,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. @@ -261,7 +426,7 @@ Example: hash ---- -This function converts and array into a hash. +This function converts an array into a hash. *Examples:* @@ -272,24 +437,39 @@ Would return: {'a'=>1,'b'=>2,'c'=>3} - *Type*: rvalue +intersection +----------- +This function returns an array an intersection of two. + +*Examples:* + + intersection(["a","b","c"],["b","c","d"]) + +Would return: ["b","c"] + 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 @@ -297,42 +477,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 @@ -345,6 +519,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 @@ -352,7 +539,6 @@ keys ---- Returns the keys of a hash as an array. - - *Type*: rvalue loadyaml @@ -371,6 +557,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 @@ -388,7 +580,6 @@ Would return: true Would return: false - - *Type*: rvalue merge @@ -405,15 +596,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 @@ -422,7 +618,6 @@ parsejson This function accepts JSON as a string and converts into the correct Puppet structure. - - *Type*: rvalue parseyaml @@ -430,6 +625,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 @@ -437,13 +648,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 @@ -470,6 +680,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 @@ -477,35 +702,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 @@ -513,7 +733,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 @@ -527,10 +746,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 @@ -619,6 +838,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. @@ -667,6 +899,17 @@ Returns the type when passed a variable. Type can be one of: - *Type*: rvalue +union +----- +This function returns a union of two arrays. + +*Examples:* + + union(["a","b","c"],["b","c","d"]) + +Would return: ["a","b","c","d"] + + unique ------ This function will remove duplicates from strings and arrays. @@ -705,6 +948,14 @@ Will return: - *Type*: rvalue +uriescape +--------- +Urlencodes a string or array of strings. +Requires either a single string or an array as an input. + + +- *Type*: rvalue + validate_absolute_path ---------------------- Validate the string represents an absolute path in the filesystem. This function works @@ -751,6 +1002,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 @@ -773,6 +1057,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 @@ -862,7 +1168,6 @@ The following values will fail, causing compilation to abort: validate_string($undefined) - - *Type*: statement values @@ -927,3 +1232,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/facter/facter_dot_d.rb b/lib/facter/facter_dot_d.rb new file mode 100644 index 0000000..e414b20 --- /dev/null +++ b/lib/facter/facter_dot_d.rb @@ -0,0 +1,202 @@ +# A Facter plugin that loads facts from /etc/facter/facts.d +# and /etc/puppetlabs/facter/facts.d. +# +# Facts can be in the form of JSON, YAML or Text files +# and any executable that returns key=value pairs. +# +# In the case of scripts you can also create a file that +# contains a cache TTL. For foo.sh store the ttl as just +# a number in foo.sh.ttl +# +# The cache is stored in /tmp/facts_cache.yaml as a mode +# 600 file and will have the end result of not calling your +# fact scripts more often than is needed + +class Facter::Util::DotD + require 'yaml' + + def initialize(dir="/etc/facts.d", cache_file="/tmp/facts_cache.yml") + @dir = dir + @cache_file = cache_file + @cache = nil + @types = {".txt" => :txt, ".json" => :json, ".yaml" => :yaml} + end + + def entries + Dir.entries(@dir).reject{|f| f =~ /^\.|\.ttl$/}.sort.map {|f| File.join(@dir, f) } + rescue + [] + end + + def fact_type(file) + extension = File.extname(file) + + type = @types[extension] || :unknown + + type = :script if type == :unknown && File.executable?(file) + + return type + end + + def txt_parser(file) + File.readlines(file).each do |line| + if line =~ /^(.+)=(.+)$/ + var = $1; val = $2 + + Facter.add(var) do + setcode { val } + end + end + end + rescue Exception => e + Facter.warn("Failed to handle #{file} as text facts: #{e.class}: #{e}") + end + + def json_parser(file) + begin + require 'json' + rescue LoadError + retry if require 'rubygems' + raise + end + + JSON.load(File.read(file)).each_pair do |f, v| + Facter.add(f) do + setcode { v } + end + end + rescue Exception => e + Facter.warn("Failed to handle #{file} as json facts: #{e.class}: #{e}") + end + + def yaml_parser(file) + require 'yaml' + + YAML.load_file(file).each_pair do |f, v| + Facter.add(f) do + setcode { v } + end + end + rescue Exception => e + Facter.warn("Failed to handle #{file} as yaml facts: #{e.class}: #{e}") + end + + def script_parser(file) + result = cache_lookup(file) + ttl = cache_time(file) + + unless result + result = Facter::Util::Resolution.exec(file) + + if ttl > 0 + Facter.debug("Updating cache for #{file}") + cache_store(file, result) + cache_save! + end + else + Facter.debug("Using cached data for #{file}") + end + + result.split("\n").each do |line| + if line =~ /^(.+)=(.+)$/ + var = $1; val = $2 + + Facter.add(var) do + setcode { val } + end + end + end + rescue Exception => e + Facter.warn("Failed to handle #{file} as script facts: #{e.class}: #{e}") + Facter.debug(e.backtrace.join("\n\t")) + end + + def cache_save! + cache = load_cache + File.open(@cache_file, "w", 0600) {|f| f.write(YAML.dump(cache)) } + rescue + end + + def cache_store(file, data) + load_cache + + @cache[file] = {:data => data, :stored => Time.now.to_i} + rescue + end + + def cache_lookup(file) + cache = load_cache + + return nil if cache.empty? + + ttl = cache_time(file) + + if cache[file] + now = Time.now.to_i + + return cache[file][:data] if ttl == -1 + return cache[file][:data] if (now - cache[file][:stored]) <= ttl + return nil + else + return nil + end + rescue + return nil + end + + def cache_time(file) + meta = file + ".ttl" + + return File.read(meta).chomp.to_i + rescue + return 0 + end + + def load_cache + unless @cache + if File.exist?(@cache_file) + @cache = YAML.load_file(@cache_file) + else + @cache = {} + end + end + + return @cache + rescue + @cache = {} + return @cache + end + + def create + entries.each do |fact| + type = fact_type(fact) + parser = "#{type}_parser" + + if respond_to?("#{type}_parser") + Facter.debug("Parsing #{fact} using #{parser}") + + send(parser, fact) + end + end + end +end + + +mdata = Facter.version.match(/(\d+)\.(\d+)\.(\d+)/) +if mdata + (major, minor, patch) = mdata.captures.map { |v| v.to_i } + if major < 2 + # Facter 1.7 introduced external facts support directly + unless major == 1 and minor > 6 + Facter::Util::DotD.new("/etc/facter/facts.d").create + Facter::Util::DotD.new("/etc/puppetlabs/facter/facts.d").create + + # Windows has a different configuration directory that defaults to a vendor + # specific sub directory of the %COMMON_APPDATA% directory. + if Dir.const_defined? 'COMMON_APPDATA' then + windows_facts_dot_d = File.join(Dir::COMMON_APPDATA, 'PuppetLabs', 'facter', 'facts.d') + Facter::Util::DotD.new(windows_facts_dot_d).create + end + end + end +end 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/base64.rb b/lib/puppet/parser/functions/base64.rb new file mode 100644 index 0000000..d9a590a --- /dev/null +++ b/lib/puppet/parser/functions/base64.rb @@ -0,0 +1,37 @@ +module Puppet::Parser::Functions + + newfunction(:base64, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args| + + Base64 encode or decode a string based on the command and the string submitted + + Usage: + + $encodestring = base64('encode','thestring') + $decodestring = base64('decode','dGhlc3RyaW5n') + + ENDHEREDOC + + require 'base64' + + raise Puppet::ParseError, ("base64(): Wrong number of arguments (#{args.length}; must be = 2)") unless args.length == 2 + + actions = ['encode','decode'] + + unless actions.include?(args[0]) + raise Puppet::ParseError, ("base64(): the first argument must be one of 'encode' or 'decode'") + end + + unless args[1].is_a?(String) + raise Puppet::ParseError, ("base64(): the second argument must be a string to base64") + end + + case args[0] + when 'encode' + result = Base64.encode64(args[1]) + when 'decode' + result = Base64.decode64(args[1]) + end + + return result + end +end diff --git a/lib/puppet/parser/functions/concat.rb b/lib/puppet/parser/functions/concat.rb new file mode 100644 index 0000000..c86aa00 --- /dev/null +++ b/lib/puppet/parser/functions/concat.rb @@ -0,0 +1,37 @@ +# +# concat.rb +# + +module Puppet::Parser::Functions + newfunction(:concat, :type => :rvalue, :doc => <<-EOS +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'] + EOS + ) do |arguments| + + # Check that 2 arguments have been given ... + raise(Puppet::ParseError, "concat(): Wrong number of arguments " + + "given (#{arguments.size} for 2)") if arguments.size != 2 + + a = arguments[0] + b = arguments[1] + + # Check that both args are arrays. + unless a.is_a?(Array) and b.is_a?(Array) + raise(Puppet::ParseError, 'concat(): Requires array to work with') + end + + result = a.concat(b) + + return result + 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/difference.rb b/lib/puppet/parser/functions/difference.rb new file mode 100644 index 0000000..cd258f7 --- /dev/null +++ b/lib/puppet/parser/functions/difference.rb @@ -0,0 +1,36 @@ +# +# difference.rb +# + +module Puppet::Parser::Functions + newfunction(:difference, :type => :rvalue, :doc => <<-EOS +This function returns the difference between two arrays. +The returned array is a copy of the original array, removing any items that +also appear in the second array. + +*Examples:* + + difference(["a","b","c"],["b","c","d"]) + +Would return: ["a"] + EOS + ) do |arguments| + + # Two arguments are required + raise(Puppet::ParseError, "difference(): Wrong number of arguments " + + "given (#{arguments.size} for 2)") if arguments.size != 2 + + first = arguments[0] + second = arguments[1] + + unless first.is_a?(Array) && second.is_a?(Array) + raise(Puppet::ParseError, 'difference(): Requires 2 arrays') + end + + result = first - second + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/lib/puppet/parser/functions/dirname.rb b/lib/puppet/parser/functions/dirname.rb new file mode 100644 index 0000000..ea8cc1e --- /dev/null +++ b/lib/puppet/parser/functions/dirname.rb @@ -0,0 +1,15 @@ +module Puppet::Parser::Functions + newfunction(:dirname, :type => :rvalue, :doc => <<-EOS + Returns the dirname of a path. + EOS + ) do |arguments| + + raise(Puppet::ParseError, "dirname(): Wrong number of arguments " + + "given (#{arguments.size} for 1)") if arguments.size < 1 + + path = arguments[0] + return File.dirname(path) + end +end + +# vim: set ts=2 sw=2 et : diff --git a/lib/puppet/parser/functions/ensure_resource.rb b/lib/puppet/parser/functions/ensure_resource.rb index fba2035..a9a1733 100644 --- a/lib/puppet/parser/functions/ensure_resource.rb +++ b/lib/puppet/parser/functions/ensure_resource.rb @@ -19,17 +19,27 @@ If the resource already exists but does not match the specified parameters, this function will attempt to recreate the resource leading to a duplicate resource definition error. +An array of resources can also be passed in and each will be created with +the type and parameters specified if it doesn't already exist. + + ensure_resource('user', ['dan','alex'], {'ensure' => 'present'}) + ENDOFDOC ) do |vals| type, title, params = vals raise(ArgumentError, 'Must specify a type') unless type raise(ArgumentError, 'Must specify a title') unless title params ||= {} - Puppet::Parser::Functions.function(:defined_with_params) - if function_defined_with_params(["#{type}[#{title}]", params]) - Puppet.debug("Resource #{type}[#{title}] not created b/c it already exists") - else - Puppet::Parser::Functions.function(:create_resources) - function_create_resources([type.capitalize, { title => params }]) + + items = [title].flatten + + items.each do |item| + Puppet::Parser::Functions.function(:defined_with_params) + if function_defined_with_params(["#{type}[#{item}]", params]) + Puppet.debug("Resource #{type}[#{item}] not created because it already exists") + else + Puppet::Parser::Functions.function(:create_resources) + function_create_resources([type.capitalize, { item => params }]) + 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/getparam.rb b/lib/puppet/parser/functions/getparam.rb new file mode 100644 index 0000000..6d51006 --- /dev/null +++ b/lib/puppet/parser/functions/getparam.rb @@ -0,0 +1,35 @@ +# Test whether a given class or definition is defined +require 'puppet/parser/functions' + +Puppet::Parser::Functions.newfunction(:getparam, + :type => :rvalue, + :doc => <<-'ENDOFDOC' +Takes a resource reference and name of the parameter and +returns value of resource's parameter. + +*Examples:* + + define example_resource($param) { + } + + example_resource { "example_resource_instance": + param => "param_value" + } + + getparam(Example_resource["example_resource_instance"], "param") + +Would return: param_value +ENDOFDOC +) do |vals| + reference, param = vals + raise(ArgumentError, 'Must specify a reference') unless reference + raise(ArgumentError, 'Must specify name of a parameter') unless param and param.instance_of? String + + return '' if param.empty? + + if resource = findresource(reference.to_s) + return resource[param] if resource[param] + end + + return '' +end diff --git a/lib/puppet/parser/functions/hash.rb b/lib/puppet/parser/functions/hash.rb index 453ba1e..8cc4823 100644 --- a/lib/puppet/parser/functions/hash.rb +++ b/lib/puppet/parser/functions/hash.rb @@ -4,7 +4,7 @@ module Puppet::Parser::Functions newfunction(:hash, :type => :rvalue, :doc => <<-EOS -This function converts and array into a hash. +This function converts an array into a hash. *Examples:* diff --git a/lib/puppet/parser/functions/intersection.rb b/lib/puppet/parser/functions/intersection.rb new file mode 100644 index 0000000..48f02e9 --- /dev/null +++ b/lib/puppet/parser/functions/intersection.rb @@ -0,0 +1,34 @@ +# +# intersection.rb +# + +module Puppet::Parser::Functions + newfunction(:intersection, :type => :rvalue, :doc => <<-EOS +This function returns an array an intersection of two. + +*Examples:* + + intersection(["a","b","c"],["b","c","d"]) + +Would return: ["b","c"] + EOS + ) do |arguments| + + # Two arguments are required + raise(Puppet::ParseError, "intersection(): Wrong number of arguments " + + "given (#{arguments.size} for 2)") if arguments.size != 2 + + first = arguments[0] + second = arguments[1] + + unless first.is_a?(Array) && second.is_a?(Array) + raise(Puppet::ParseError, 'intersection(): Requires 2 arrays') + end + + result = first & second + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/lib/puppet/parser/functions/is_float.rb b/lib/puppet/parser/functions/is_float.rb index 2fc05ba..911f3c2 100644 --- a/lib/puppet/parser/functions/is_float.rb +++ b/lib/puppet/parser/functions/is_float.rb @@ -15,7 +15,7 @@ Returns true if the variable passed to this function is a float. value = arguments[0] - if value != value.to_f.to_s then + if value != value.to_f.to_s and !value.is_a? Float then return false else return true 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/is_integer.rb b/lib/puppet/parser/functions/is_integer.rb index 8ee34f6..6b29e98 100644 --- a/lib/puppet/parser/functions/is_integer.rb +++ b/lib/puppet/parser/functions/is_integer.rb @@ -15,7 +15,7 @@ Returns true if the variable returned to this string is an integer. value = arguments[0] - if value != value.to_i.to_s then + if value != value.to_i.to_s and !value.is_a? Fixnum then return false else return true diff --git a/lib/puppet/parser/functions/is_numeric.rb b/lib/puppet/parser/functions/is_numeric.rb index ce13ece..abf0321 100644 --- a/lib/puppet/parser/functions/is_numeric.rb +++ b/lib/puppet/parser/functions/is_numeric.rb @@ -15,7 +15,7 @@ Returns true if the variable passed to this function is a number. value = arguments[0] - if value == value.to_f.to_s or value == value.to_i.to_s then + if value == value.to_f.to_s or value == value.to_i.to_s or value.is_a? Numeric then return true else return false 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/merge.rb b/lib/puppet/parser/functions/merge.rb index 6ec085e..1b39f20 100644 --- a/lib/puppet/parser/functions/merge.rb +++ b/lib/puppet/parser/functions/merge.rb @@ -22,6 +22,7 @@ module Puppet::Parser::Functions accumulator = Hash.new # Merge into the accumulator hash args.each do |arg| + next if arg.is_a? String and arg.empty? # empty string is synonym for puppet's undef unless arg.is_a?(Hash) raise Puppet::ParseError, "merge: unexpected argument type #{arg.class}, only expects hash arguments" 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/parser/functions/union.rb b/lib/puppet/parser/functions/union.rb new file mode 100644 index 0000000..c91bb80 --- /dev/null +++ b/lib/puppet/parser/functions/union.rb @@ -0,0 +1,34 @@ +# +# union.rb +# + +module Puppet::Parser::Functions + newfunction(:union, :type => :rvalue, :doc => <<-EOS +This function returns a union of two arrays. + +*Examples:* + + union(["a","b","c"],["b","c","d"]) + +Would return: ["a","b","c","d"] + EOS + ) do |arguments| + + # Two arguments are required + raise(Puppet::ParseError, "union(): Wrong number of arguments " + + "given (#{arguments.size} for 2)") if arguments.size != 2 + + first = arguments[0] + second = arguments[1] + + unless first.is_a?(Array) && second.is_a?(Array) + raise(Puppet::ParseError, 'union(): Requires 2 arrays') + end + + result = first | second + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/lib/puppet/parser/functions/validate_augeas.rb b/lib/puppet/parser/functions/validate_augeas.rb new file mode 100644 index 0000000..154d660 --- /dev/null +++ b/lib/puppet/parser/functions/validate_augeas.rb @@ -0,0 +1,81 @@ +module Puppet::Parser::Functions + newfunction(:validate_augeas, :doc => <<-'ENDHEREDOC') do |args| + 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') + + ENDHEREDOC + unless Puppet.features.augeas? + raise Puppet::ParseError, ("validate_augeas(): this function requires the augeas feature. See http://projects.puppetlabs.com/projects/puppet/wiki/Puppet_Augeas#Pre-requisites for how to activate it.") + end + + if (args.length < 2) or (args.length > 4) then + raise Puppet::ParseError, ("validate_augeas(): wrong number of arguments (#{args.length}; must be 2, 3, or 4)") + end + + msg = args[3] || "validate_augeas(): Failed to validate content against #{args[1].inspect}" + + require 'augeas' + aug = Augeas::open(nil, nil, Augeas::NO_MODL_AUTOLOAD) + begin + content = args[0] + + # Test content in a temporary file + tmpfile = Tempfile.new("validate_augeas") + begin + tmpfile.write(content) + ensure + tmpfile.close + end + + # Check for syntax + lens = args[1] + aug.transform( + :lens => lens, + :name => 'Validate_augeas', + :incl => tmpfile.path + ) + aug.load! + + unless aug.match("/augeas/files#{tmpfile.path}//error").empty? + error = aug.get("/augeas/files#{tmpfile.path}//error/message") + msg += " with error: #{error}" + raise Puppet::ParseError, (msg) + end + + # Launch unit tests + tests = args[2] || [] + aug.defvar('file', "/files#{tmpfile.path}") + tests.each do |t| + msg += " testing path #{t}" + raise Puppet::ParseError, (msg) unless aug.match(t).empty? + end + ensure + aug.close + tmpfile.unlink + end + end +end diff --git a/lib/puppet/parser/functions/validate_cmd.rb b/lib/puppet/parser/functions/validate_cmd.rb new file mode 100644 index 0000000..344a80c --- /dev/null +++ b/lib/puppet/parser/functions/validate_cmd.rb @@ -0,0 +1,47 @@ +require 'puppet/util/execution' + +module Puppet::Parser::Functions + newfunction(:validate_cmd, :doc => <<-'ENDHEREDOC') do |args| + 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') + + ENDHEREDOC + if (args.length < 2) or (args.length > 3) then + raise Puppet::ParseError, ("validate_cmd(): wrong number of arguments (#{args.length}; must be 2 or 3)") + end + + msg = args[2] || "validate_cmd(): failed to validate content with command #{args[1].inspect}" + + content = args[0] + checkscript = args[1] + + # Test content in a temporary file + tmpfile = Tempfile.new("validate_cmd") + begin + tmpfile.write(content) + if Puppet::Util::Execution.respond_to?('execute') + Puppet::Util::Execution.execute("#{checkscript} #{tmpfile.path}") + else + Puppet::Util.execute("#{checkscript} #{tmpfile.path}") + end + rescue Puppet::ExecutionFailure => detail + msg += "\n#{detail}" + raise Puppet::ParseError, msg + ensure + tmpfile.unlink + end + end +end diff --git a/lib/puppet/provider/file_line/ruby.rb b/lib/puppet/provider/file_line/ruby.rb index e21eaa8..a3219d3 100644 --- a/lib/puppet/provider/file_line/ruby.rb +++ b/lib/puppet/provider/file_line/ruby.rb @@ -34,7 +34,7 @@ Puppet::Type.type(:file_line).provide(:ruby) do def handle_create_with_match() regex = resource[:match] ? Regexp.new(resource[:match]) : nil - match_count = lines.select { |l| regex.match(l) }.count + match_count = lines.select { |l| regex.match(l) }.size if match_count > 1 raise Puppet::Error, "More than one line in file '#{resource[:path]}' matches pattern '#{resource[:match]}'" end 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/functions/ensure_resource_spec.rb b/spec/functions/ensure_resource_spec.rb index 611666e..2e8aefc 100644 --- a/spec/functions/ensure_resource_spec.rb +++ b/spec/functions/ensure_resource_spec.rb @@ -4,17 +4,16 @@ require 'spec_helper' require 'rspec-puppet' describe 'ensure_resource' do describe 'when a type or title is not specified' do - it do - should run.with_params().and_raise_error(ArgumentError) - should run.with_params(['type']).and_raise_error(ArgumentError) - end + it { should run.with_params().and_raise_error(ArgumentError) } + it { should run.with_params(['type']).and_raise_error(ArgumentError) } end + describe 'when compared against a resource with no attributes' do let :pre_condition do 'user { "dan": }' end - it do - should run.with_params('user', 'dan', {}) + it "should contain the the ensured resources" do + subject.should run.with_params('user', 'dan', {}) compiler.catalog.resource('User[dan]').to_s.should == 'User[dan]' end end @@ -23,18 +22,43 @@ describe 'ensure_resource' do let :pre_condition do 'user { "dan": ensure => present, shell => "/bin/csh", managehome => false}' end - it do - # these first three should not fail - should run.with_params('User', 'dan', {}) - should run.with_params('User', 'dan', '') - should run.with_params('User', 'dan', {'ensure' => 'present'}) - should run.with_params('User', 'dan', - {'ensure' => 'present', 'managehome' => false} - ) - # test that this fails - should run.with_params('User', 'dan', - {'ensure' => 'absent', 'managehome' => false} - ).and_raise_error(Puppet::Error) + # these first three should not fail + it { should run.with_params('User', 'dan', {}) } + it { should run.with_params('User', 'dan', '') } + it { should run.with_params('User', 'dan', {'ensure' => 'present'}) } + it { should run.with_params('User', 'dan', {'ensure' => 'present', 'managehome' => false}) } + # test that this fails + it { should run.with_params('User', 'dan', {'ensure' => 'absent', 'managehome' => false}).and_raise_error(Puppet::Error) } + end + + describe 'when an array of new resources are passed in' do + it "should contain the ensured resources" do + subject.should run.with_params('User', ['dan', 'alex'], {}) + compiler.catalog.resource('User[dan]').to_s.should == 'User[dan]' + compiler.catalog.resource('User[alex]').to_s.should == 'User[alex]' + end + end + + describe 'when an array of existing resources is compared against existing resources' do + let :pre_condition do + 'user { "dan": ensure => present; "alex": ensure => present }' + end + it "should return the existing resources" do + subject.should run.with_params('User', ['dan', 'alex'], {}) + compiler.catalog.resource('User[dan]').to_s.should == 'User[dan]' + compiler.catalog.resource('User[alex]').to_s.should == 'User[alex]' + end + end + + describe 'when compared against existing resources with attributes' do + let :pre_condition do + 'user { "dan": ensure => present; "alex": ensure => present }' end + # These should not fail + it { should run.with_params('User', ['dan', 'alex'], {}) } + it { should run.with_params('User', ['dan', 'alex'], '') } + it { should run.with_params('User', ['dan', 'alex'], {'ensure' => 'present'}) } + # This should fail + it { should run.with_params('User', ['dan', 'alex'], {'ensure' => 'absent'}).and_raise_error(Puppet::Error) } end end diff --git a/spec/functions/getparam_spec.rb b/spec/functions/getparam_spec.rb new file mode 100644 index 0000000..d9c50a6 --- /dev/null +++ b/spec/functions/getparam_spec.rb @@ -0,0 +1,34 @@ +#! /usr/bin/env ruby -S rspec +require 'spec_helper' + +require 'rspec-puppet' +describe 'getparam' do + describe 'when a resource is not specified' do + it do + should run.with_params().and_raise_error(ArgumentError) + should run.with_params('User[dan]').and_raise_error(ArgumentError) + should run.with_params('User[dan]', {}).and_raise_error(ArgumentError) + should run.with_params('User[dan]', '').and_return('') + end + end + describe 'when compared against a resource with no params' do + let :pre_condition do + 'user { "dan": }' + end + it do + should run.with_params('User[dan]', 'shell').and_return('') + end + end + + describe 'when compared against a resource with params' do + let :pre_condition do + 'user { "dan": ensure => present, shell => "/bin/sh", managehome => false}' + end + it do + should run.with_params('User[dan]', 'shell').and_return('/bin/sh') + should run.with_params('User[dan]', '').and_return('') + should run.with_params('User[dan]', 'ensure').and_return('present') + should run.with_params('User[dan]', 'managehome').and_return(false) + end + end +end diff --git a/spec/unit/facter/pe_required_facts_spec.rb b/spec/unit/facter/pe_required_facts_spec.rb new file mode 100644 index 0000000..f219b37 --- /dev/null +++ b/spec/unit/facter/pe_required_facts_spec.rb @@ -0,0 +1,69 @@ +# Puppet Enterprise requires the following facts to be set in order to operate. +# These facts are set using the file ???? and the two facts are +# `fact_stomp_port`, and `fact_stomp_server`. +# + +require 'spec_helper' + +describe "External facts in /etc/puppetlabs/facter/facts.d/puppet_enterprise_installer.txt" do + context "With Facter 1.6.17 which does not have external facts support" do + before :each do + Facter.stubs(:version).returns("1.6.17") + # Stub out the filesystem for stdlib + Dir.stubs(:entries).with("/etc/puppetlabs/facter/facts.d"). + returns(['puppet_enterprise_installer.txt']) + Dir.stubs(:entries).with("/etc/facter/facts.d").returns([]) + File.stubs(:readlines).with('/etc/puppetlabs/facter/facts.d/puppet_enterprise_installer.txt'). + returns([ + "fact_stomp_port=61613\n", + "fact_stomp_server=puppetmaster.acme.com\n", + "fact_is_puppetagent=true\n", + "fact_is_puppetmaster=false\n", + "fact_is_puppetca=false\n", + "fact_is_puppetconsole=false\n", + ]) + if Facter.collection.respond_to? :load + Facter.collection.load(:facter_dot_d) + else + Facter.collection.loader.load(:facter_dot_d) + end + end + + it 'defines fact_stomp_port' do + Facter.fact(:fact_stomp_port).value.should == '61613' + end + it 'defines fact_stomp_server' do + Facter.fact(:fact_stomp_server).value.should == 'puppetmaster.acme.com' + end + it 'defines fact_is_puppetagent' do + Facter.fact(:fact_is_puppetagent).value.should == 'true' + end + it 'defines fact_is_puppetmaster' do + Facter.fact(:fact_is_puppetmaster).value.should == 'false' + end + it 'defines fact_is_puppetca' do + Facter.fact(:fact_is_puppetca).value.should == 'false' + end + it 'defines fact_is_puppetconsole' do + Facter.fact(:fact_is_puppetconsole).value.should == 'false' + end + end + + [ '1.7.1', '2.0.1' ].each do |v| + context "With Facter #{v} which has external facts support" do + before :each do + Facter.stubs(:version).returns(v) + end + + it 'does not call Facter::Util::DotD.new' do + Facter::Util::DotD.expects(:new).never + + if Facter.collection.respond_to? :load + Facter.collection.load(:facter_dot_d) + else + Facter.collection.loader.load(:facter_dot_d) + end + end + end + 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/base64_spec.rb b/spec/unit/puppet/parser/functions/base64_spec.rb new file mode 100755 index 0000000..5faa5e6 --- /dev/null +++ b/spec/unit/puppet/parser/functions/base64_spec.rb @@ -0,0 +1,34 @@ +#! /usr/bin/env ruby -S rspec + +require 'spec_helper' + +describe "the base64 function" do + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + it "should exist" do + Puppet::Parser::Functions.function("base64").should == "function_base64" + end + + it "should raise a ParseError if there are other than 2 arguments" do + expect { scope.function_base64([]) }.to(raise_error(Puppet::ParseError)) + expect { scope.function_base64(["asdf"]) }.to(raise_error(Puppet::ParseError)) + expect { scope.function_base64(["asdf","moo","cow"]) }.to(raise_error(Puppet::ParseError)) + end + + it "should raise a ParseError if argument 1 isn't 'encode' or 'decode'" do + expect { scope.function_base64(["bees","astring"]) }.to(raise_error(Puppet::ParseError, /first argument must be one of/)) + end + + it "should raise a ParseError if argument 2 isn't a string" do + expect { scope.function_base64(["encode",["2"]]) }.to(raise_error(Puppet::ParseError, /second argument must be a string/)) + end + + it "should encode a encoded string" do + result = scope.function_base64(["encode",'thestring']) + result.should =~ /\AdGhlc3RyaW5n\n\Z/ + end + it "should decode a base64 encoded string" do + result = scope.function_base64(["decode",'dGhlc3RyaW5n']) + result.should == 'thestring' + end +end diff --git a/spec/unit/puppet/parser/functions/concat_spec.rb b/spec/unit/puppet/parser/functions/concat_spec.rb new file mode 100644 index 0000000..123188b --- /dev/null +++ b/spec/unit/puppet/parser/functions/concat_spec.rb @@ -0,0 +1,15 @@ +#! /usr/bin/env ruby -S rspec +require 'spec_helper' + +describe "the concat function" do + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + it "should raise a ParseError if there is less than 1 arguments" do + lambda { scope.function_concat([]) }.should( raise_error(Puppet::ParseError)) + end + + it "should be able to concat an array" do + result = scope.function_concat([['1','2','3'],['4','5','6']]) + result.should(eq(['1','2','3','4','5','6'])) + 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/difference_spec.rb b/spec/unit/puppet/parser/functions/difference_spec.rb new file mode 100644 index 0000000..9feff09 --- /dev/null +++ b/spec/unit/puppet/parser/functions/difference_spec.rb @@ -0,0 +1,19 @@ +#! /usr/bin/env ruby -S rspec +require 'spec_helper' + +describe "the difference function" do + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + it "should exist" do + Puppet::Parser::Functions.function("difference").should == "function_difference" + end + + it "should raise a ParseError if there are fewer than 2 arguments" do + lambda { scope.function_difference([]) }.should( raise_error(Puppet::ParseError) ) + end + + it "should return the difference between two arrays" do + result = scope.function_difference([["a","b","c"],["b","c","d"]]) + result.should(eq(["a"])) + end +end diff --git a/spec/unit/puppet/parser/functions/dirname_spec.rb b/spec/unit/puppet/parser/functions/dirname_spec.rb new file mode 100755 index 0000000..fb3b4fe --- /dev/null +++ b/spec/unit/puppet/parser/functions/dirname_spec.rb @@ -0,0 +1,24 @@ +#! /usr/bin/env ruby -S rspec +require 'spec_helper' + +describe "the dirname function" do + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + it "should exist" do + Puppet::Parser::Functions.function("dirname").should == "function_dirname" + end + + it "should raise a ParseError if there is less than 1 arguments" do + lambda { scope.function_dirname([]) }.should( raise_error(Puppet::ParseError)) + end + + it "should return dirname for an absolute path" do + result = scope.function_dirname(['/path/to/a/file.ext']) + result.should(eq('/path/to/a')) + end + + it "should return dirname for a relative path" do + result = scope.function_dirname(['path/to/a/file.ext']) + result.should(eq('path/to/a')) + 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/get_module_path_spec.rb b/spec/unit/puppet/parser/functions/get_module_path_spec.rb index e761706..486bef6 100644 --- a/spec/unit/puppet/parser/functions/get_module_path_spec.rb +++ b/spec/unit/puppet/parser/functions/get_module_path_spec.rb @@ -15,11 +15,11 @@ describe Puppet::Parser::Functions.function(:get_module_path) do end it 'should only allow one argument' do - expect { scope.function_get_module_path([]) }.should raise_error(Puppet::ParseError, /Wrong number of arguments, expects one/) - expect { scope.function_get_module_path(['1','2','3']) }.should raise_error(Puppet::ParseError, /Wrong number of arguments, expects one/) + expect { scope.function_get_module_path([]) }.to raise_error(Puppet::ParseError, /Wrong number of arguments, expects one/) + expect { scope.function_get_module_path(['1','2','3']) }.to raise_error(Puppet::ParseError, /Wrong number of arguments, expects one/) end it 'should raise an exception when the module cannot be found' do - expect { scope.function_get_module_path(['foo']) }.should raise_error(Puppet::ParseError, /Could not find module/) + expect { scope.function_get_module_path(['foo']) }.to raise_error(Puppet::ParseError, /Could not find module/) end describe 'when locating a module' do let(:modulepath) { "/tmp/does_not_exist" } diff --git a/spec/unit/puppet/parser/functions/intersection_spec.rb b/spec/unit/puppet/parser/functions/intersection_spec.rb new file mode 100644 index 0000000..fd44f7f --- /dev/null +++ b/spec/unit/puppet/parser/functions/intersection_spec.rb @@ -0,0 +1,19 @@ +#! /usr/bin/env ruby -S rspec +require 'spec_helper' + +describe "the intersection function" do + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + it "should exist" do + Puppet::Parser::Functions.function("intersection").should == "function_intersection" + end + + it "should raise a ParseError if there are fewer than 2 arguments" do + lambda { scope.function_intersection([]) }.should( raise_error(Puppet::ParseError) ) + end + + it "should return the intersection of two arrays" do + result = scope.function_intersection([["a","b","c"],["b","c","d"]]) + result.should(eq(["b","c"])) + end +end diff --git a/spec/unit/puppet/parser/functions/is_float_spec.rb b/spec/unit/puppet/parser/functions/is_float_spec.rb index 2f527d9..b7d73b0 100644 --- a/spec/unit/puppet/parser/functions/is_float_spec.rb +++ b/spec/unit/puppet/parser/functions/is_float_spec.rb @@ -26,4 +26,8 @@ describe "the is_float function" do result = scope.function_is_float(["3"]) result.should(eq(false)) end + it "should return true if a float is created from an arithmetical operation" do + result = scope.function_is_float([3.2*2]) + result.should(eq(true)) + 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/is_integer_spec.rb b/spec/unit/puppet/parser/functions/is_integer_spec.rb index 5afbba4..4335795 100644 --- a/spec/unit/puppet/parser/functions/is_integer_spec.rb +++ b/spec/unit/puppet/parser/functions/is_integer_spec.rb @@ -26,4 +26,9 @@ describe "the is_integer function" do result = scope.function_is_integer(["asdf"]) result.should(eq(false)) end + + it "should return true if an integer is created from an arithmetical operation" do + result = scope.function_is_integer([3*2]) + result.should(eq(true)) + end end diff --git a/spec/unit/puppet/parser/functions/is_numeric_spec.rb b/spec/unit/puppet/parser/functions/is_numeric_spec.rb index 4078b37..d7440fb 100644 --- a/spec/unit/puppet/parser/functions/is_numeric_spec.rb +++ b/spec/unit/puppet/parser/functions/is_numeric_spec.rb @@ -22,6 +22,16 @@ describe "the is_numeric function" do result.should(eq(true)) end + it "should return true if an integer is created from an arithmetical operation" do + result = scope.function_is_numeric([3*2]) + result.should(eq(true)) + end + + it "should return true if a float is created from an arithmetical operation" do + result = scope.function_is_numeric([3.2*2]) + result.should(eq(true)) + end + it "should return false if a string" do result = scope.function_is_numeric(["asdf"]) result.should(eq(false)) 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/merge_spec.rb b/spec/unit/puppet/parser/functions/merge_spec.rb index db7d837..8a170bb 100644 --- a/spec/unit/puppet/parser/functions/merge_spec.rb +++ b/spec/unit/puppet/parser/functions/merge_spec.rb @@ -25,7 +25,12 @@ describe Puppet::Parser::Functions.function(:merge) do describe 'when calling merge on the scope instance' do it 'should require all parameters are hashes' do - expect { new_hash = scope.function_merge([{}, '2'])}.should raise_error(Puppet::ParseError, /unexpected argument type String/) + expect { new_hash = scope.function_merge([{}, '2'])}.to raise_error(Puppet::ParseError, /unexpected argument type String/) + expect { new_hash = scope.function_merge([{}, 2])}.to raise_error(Puppet::ParseError, /unexpected argument type Fixnum/) + end + + it 'should accept empty strings as puppet undef' do + expect { new_hash = scope.function_merge([{}, ''])}.not_to raise_error(Puppet::ParseError, /unexpected argument type String/) end it 'should be able to merge two hashes' do 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/str2saltedsha512_spec.rb b/spec/unit/puppet/parser/functions/str2saltedsha512_spec.rb index a692c31..df8fb8e 100644 --- a/spec/unit/puppet/parser/functions/str2saltedsha512_spec.rb +++ b/spec/unit/puppet/parser/functions/str2saltedsha512_spec.rb @@ -9,11 +9,11 @@ describe "the str2saltedsha512 function" do end it "should raise a ParseError if there is less than 1 argument" do - expect { scope.function_str2saltedsha512([]) }.should( raise_error(Puppet::ParseError) ) + expect { scope.function_str2saltedsha512([]) }.to( raise_error(Puppet::ParseError) ) end it "should raise a ParseError if there is more than 1 argument" do - expect { scope.function_str2saltedsha512(['foo', 'bar', 'baz']) }.should( raise_error(Puppet::ParseError) ) + expect { scope.function_str2saltedsha512(['foo', 'bar', 'baz']) }.to( raise_error(Puppet::ParseError) ) end it "should return a salted-sha512 password hash 136 characters in length" do @@ -22,7 +22,7 @@ describe "the str2saltedsha512 function" do end it "should raise an error if you pass a non-string password" do - expect { scope.function_str2saltedsha512([1234]) }.should( raise_error(Puppet::ParseError) ) + expect { scope.function_str2saltedsha512([1234]) }.to( raise_error(Puppet::ParseError) ) end it "should generate a valid password" do 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 diff --git a/spec/unit/puppet/parser/functions/union_spec.rb b/spec/unit/puppet/parser/functions/union_spec.rb new file mode 100644 index 0000000..0d282ca --- /dev/null +++ b/spec/unit/puppet/parser/functions/union_spec.rb @@ -0,0 +1,19 @@ +#! /usr/bin/env ruby -S rspec +require 'spec_helper' + +describe "the union function" do + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + it "should exist" do + Puppet::Parser::Functions.function("union").should == "function_union" + end + + it "should raise a ParseError if there are fewer than 2 arguments" do + lambda { scope.function_union([]) }.should( raise_error(Puppet::ParseError) ) + end + + it "should join two arrays together" do + result = scope.function_union([["a","b","c"],["b","c","d"]]) + result.should(eq(["a","b","c","d"])) + end +end diff --git a/spec/unit/puppet/parser/functions/validate_array_spec.rb b/spec/unit/puppet/parser/functions/validate_array_spec.rb index 8eee72a..4b31cfd 100644 --- a/spec/unit/puppet/parser/functions/validate_array_spec.rb +++ b/spec/unit/puppet/parser/functions/validate_array_spec.rb @@ -9,12 +9,12 @@ describe Puppet::Parser::Functions.function(:validate_array) do %w{ true false }.each do |the_string| it "should not compile when #{the_string} is a string" do Puppet[:code] = "validate_array('#{the_string}')" - expect { scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not an Array/) + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not an Array/) end it "should not compile when #{the_string} is a bare word" do Puppet[:code] = "validate_array(#{the_string})" - expect { scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not an Array/) + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not an Array/) end end @@ -32,7 +32,7 @@ describe Puppet::Parser::Functions.function(:validate_array) do $foo = undef validate_array($foo) ENDofPUPPETcode - expect { scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not an Array/) + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not an Array/) end end end diff --git a/spec/unit/puppet/parser/functions/validate_augeas_spec.rb b/spec/unit/puppet/parser/functions/validate_augeas_spec.rb new file mode 100644 index 0000000..ab5c140 --- /dev/null +++ b/spec/unit/puppet/parser/functions/validate_augeas_spec.rb @@ -0,0 +1,102 @@ +require 'spec_helper' + +describe Puppet::Parser::Functions.function(:validate_augeas), :if => Puppet.features.augeas? do + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + # The subject of these examplres is the method itself. + subject do + # This makes sure the function is loaded within each test + function_name = Puppet::Parser::Functions.function(:validate_augeas) + scope.method(function_name) + end + + context 'Using Puppet::Parser::Scope.new' do + + describe 'Garbage inputs' do + inputs = [ + [ nil ], + [ [ nil ] ], + [ { 'foo' => 'bar' } ], + [ { } ], + [ '' ], + [ "one", "one", "MSG to User", "4th arg" ], + ] + + inputs.each do |input| + it "validate_augeas(#{input.inspect}) should fail" do + expect { subject.call [input] }.to raise_error Puppet::ParseError + end + end + end + + describe 'Valid inputs' do + inputs = [ + [ "root:x:0:0:root:/root:/bin/bash\n", 'Passwd.lns' ], + [ "proc /proc proc nodev,noexec,nosuid 0 0\n", 'Fstab.lns'], + ] + + inputs.each do |input| + it "validate_augeas(#{input.inspect}) should not fail" do + expect { subject.call input }.not_to raise_error + end + end + end + + describe "Valid inputs which should raise an exception without a message" do + # The intent here is to make sure valid inputs raise exceptions when they + # don't specify an error message to display. This is the behvior in + # 2.2.x and prior. + inputs = [ + [ "root:x:0:0:root\n", 'Passwd.lns' ], + [ "127.0.1.1\n", 'Hosts.lns' ], + ] + + inputs.each do |input| + it "validate_augeas(#{input.inspect}) should fail" do + expect { subject.call input }.to raise_error /validate_augeas.*?matched less than it should/ + end + end + end + + describe "Nicer Error Messages" do + # The intent here is to make sure the function returns the 3rd argument + # in the exception thrown + inputs = [ + [ "root:x:0:0:root\n", 'Passwd.lns', [], 'Failed to validate passwd content' ], + [ "127.0.1.1\n", 'Hosts.lns', [], 'Wrong hosts content' ], + ] + + inputs.each do |input| + it "validate_augeas(#{input.inspect}) should fail" do + expect { subject.call input }.to raise_error /#{input[2]}/ + end + end + end + + describe "Passing simple unit tests" do + inputs = [ + [ "root:x:0:0:root:/root:/bin/bash\n", 'Passwd.lns', ['$file/foobar']], + [ "root:x:0:0:root:/root:/bin/bash\n", 'Passwd.lns', ['$file/root/shell[.="/bin/sh"]', 'foobar']], + ] + + inputs.each do |input| + it "validate_augeas(#{input.inspect}) should fail" do + expect { subject.call input }.not_to raise_error + end + end + end + + describe "Failing simple unit tests" do + inputs = [ + [ "foobar:x:0:0:root:/root:/bin/bash\n", 'Passwd.lns', ['$file/foobar']], + [ "root:x:0:0:root:/root:/bin/sh\n", 'Passwd.lns', ['$file/root/shell[.="/bin/sh"]', 'foobar']], + ] + + inputs.each do |input| + it "validate_augeas(#{input.inspect}) should fail" do + expect { subject.call input }.to raise_error /testing path/ + end + end + end + end +end diff --git a/spec/unit/puppet/parser/functions/validate_bool_spec.rb b/spec/unit/puppet/parser/functions/validate_bool_spec.rb index 31ab8fb..261fb23 100644 --- a/spec/unit/puppet/parser/functions/validate_bool_spec.rb +++ b/spec/unit/puppet/parser/functions/validate_bool_spec.rb @@ -10,7 +10,7 @@ describe Puppet::Parser::Functions.function(:validate_bool) do it "should not compile when #{the_string} is a string" do Puppet[:code] = "validate_bool('#{the_string}')" - expect { scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not a boolean/) + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not a boolean/) end it "should compile when #{the_string} is a bare word" do @@ -22,12 +22,12 @@ describe Puppet::Parser::Functions.function(:validate_bool) do it "should not compile when an arbitrary string is passed" do Puppet[:code] = 'validate_bool("jeff and dan are awesome")' - expect { scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not a boolean/) + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not a boolean/) end it "should not compile when no arguments are passed" do Puppet[:code] = 'validate_bool()' - expect { scope.compiler.compile }.should raise_error(Puppet::ParseError, /wrong number of arguments/) + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /wrong number of arguments/) end it "should compile when multiple boolean arguments are passed" do @@ -45,7 +45,7 @@ describe Puppet::Parser::Functions.function(:validate_bool) do $bar = false validate_bool($foo, $bar, true, false, 'jeff') ENDofPUPPETcode - expect { scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not a boolean/) + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not a boolean/) end end end diff --git a/spec/unit/puppet/parser/functions/validate_cmd_spec.rb b/spec/unit/puppet/parser/functions/validate_cmd_spec.rb new file mode 100644 index 0000000..69ea7f4 --- /dev/null +++ b/spec/unit/puppet/parser/functions/validate_cmd_spec.rb @@ -0,0 +1,81 @@ +require 'spec_helper' + +describe Puppet::Parser::Functions.function(:validate_cmd) do + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + # The subject of these examplres is the method itself. + subject do + # This makes sure the function is loaded within each test + function_name = Puppet::Parser::Functions.function(:validate_cmd) + scope.method(function_name) + end + + context 'Using Puppet::Parser::Scope.new' do + + describe 'Garbage inputs' do + inputs = [ + [ nil ], + [ [ nil ] ], + [ { 'foo' => 'bar' } ], + [ { } ], + [ '' ], + [ "one", "one", "MSG to User", "4th arg" ], + ] + + inputs.each do |input| + it "validate_cmd(#{input.inspect}) should fail" do + expect { subject.call [input] }.to raise_error Puppet::ParseError + end + end + end + + describe 'Valid inputs' do + inputs = [ + [ '/full/path/to/something', '/bin/echo' ], + [ '/full/path/to/something', '/bin/cat' ], + ] + + inputs.each do |input| + it "validate_cmd(#{input.inspect}) should not fail" do + expect { subject.call input }.not_to raise_error + end + end + end + + describe "Valid inputs which should raise an exception without a message" do + # The intent here is to make sure valid inputs raise exceptions when they + # don't specify an error message to display. This is the behvior in + # 2.2.x and prior. + inputs = [ + [ "hello", "/bin/false" ], + ] + + inputs.each do |input| + it "validate_cmd(#{input.inspect}) should fail" do + expect { subject.call input }.to raise_error /validate_cmd.*?failed to validate content with command/ + end + end + end + + describe "Nicer Error Messages" do + # The intent here is to make sure the function returns the 3rd argument + # in the exception thrown + inputs = [ + [ "hello", [ "bye", "later", "adios" ], "MSG to User" ], + [ "greetings", "salutations", "Error, greetings does not match salutations" ], + ] + + inputs.each do |input| + it "validate_cmd(#{input.inspect}) should fail" do + expect { subject.call input }.to raise_error /#{input[2]}/ + end + end + end + + describe "Test output message" do + it "validate_cmd('whatever', 'kthnksbye') should fail" do + expect { subject.call ['whatever', 'kthnksbye'] }.to raise_error /kthnksbye.* returned 1/ + end + end + end +end diff --git a/spec/unit/puppet/parser/functions/validate_hash_spec.rb b/spec/unit/puppet/parser/functions/validate_hash_spec.rb index 06d77a1..a0c35c2 100644 --- a/spec/unit/puppet/parser/functions/validate_hash_spec.rb +++ b/spec/unit/puppet/parser/functions/validate_hash_spec.rb @@ -11,12 +11,12 @@ describe Puppet::Parser::Functions.function(:validate_hash) do it "should not compile when #{the_string} is a string" do Puppet[:code] = "validate_hash('#{the_string}')" - expect { scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not a Hash/) + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not a Hash/) end it "should not compile when #{the_string} is a bare word" do Puppet[:code] = "validate_hash(#{the_string})" - expect { scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not a Hash/) + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not a Hash/) end end @@ -35,7 +35,7 @@ describe Puppet::Parser::Functions.function(:validate_hash) do $foo = undef validate_hash($foo) ENDofPUPPETcode - expect { scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not a Hash/) + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not a Hash/) end end diff --git a/spec/unit/puppet/parser/functions/validate_slength_spec.rb b/spec/unit/puppet/parser/functions/validate_slength_spec.rb index eccf908..b363e7a 100755 --- a/spec/unit/puppet/parser/functions/validate_slength_spec.rb +++ b/spec/unit/puppet/parser/functions/validate_slength_spec.rb @@ -35,7 +35,7 @@ describe "the validate_slength function" do end it "should fail if you pass something other than a string or array" do - expect { scope.function_validate_slength([Hash.new["moo" => "7"],6]) }.to(raise_error(Puppet::ParseError), /please pass a string, or an array of strings/) + expect { scope.function_validate_slength([Hash.new["moo" => "7"],6]) }.to(raise_error(Puppet::ParseError, /please pass a string, or an array of strings/)) end it "should not fail if string is smaller or equal to size" do diff --git a/spec/unit/puppet/parser/functions/validate_string_spec.rb b/spec/unit/puppet/parser/functions/validate_string_spec.rb index 007b4ca..3b4fb3e 100644 --- a/spec/unit/puppet/parser/functions/validate_string_spec.rb +++ b/spec/unit/puppet/parser/functions/validate_string_spec.rb @@ -29,7 +29,7 @@ describe Puppet::Parser::Functions.function(:validate_string) do it "should not compile when #{the_string} is a bare word" do Puppet[:code] = "validate_string(#{the_string})" - expect { scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not a string/) + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not a string/) end end diff --git a/spec/unit/puppet/type/file_line_spec.rb b/spec/unit/puppet/type/file_line_spec.rb index 0cd8a26..edc64bd 100644 --- a/spec/unit/puppet/type/file_line_spec.rb +++ b/spec/unit/puppet/type/file_line_spec.rb @@ -37,13 +37,13 @@ describe Puppet::Type.type(:file_line) do file_line[:path].should == '/tmp/path' end it 'should not accept unqualified path' do - expect { file_line[:path] = 'file' }.should raise_error(Puppet::Error, /File paths must be fully qualified/) + expect { file_line[:path] = 'file' }.to raise_error(Puppet::Error, /File paths must be fully qualified/) end it 'should require that a line is specified' do - expect { Puppet::Type.type(:file_line).new(:name => 'foo', :path => '/tmp/file') }.should raise_error(Puppet::Error, /Both line and path are required attributes/) + expect { Puppet::Type.type(:file_line).new(:name => 'foo', :path => '/tmp/file') }.to raise_error(Puppet::Error, /Both line and path are required attributes/) end it 'should require that a file is specified' do - expect { Puppet::Type.type(:file_line).new(:name => 'foo', :line => 'path') }.should raise_error(Puppet::Error, /Both line and path are required attributes/) + expect { Puppet::Type.type(:file_line).new(:name => 'foo', :line => 'path') }.to raise_error(Puppet::Error, /Both line and path are required attributes/) end it 'should default to ensure => present' do file_line[:ensure].should eq :present |