Merge "Sync stdlib module from puppetlabs"

This commit is contained in:
Jenkins 2015-06-12 18:09:36 +00:00 committed by Gerrit Code Review
commit be3494e27c
198 changed files with 4481 additions and 1963 deletions

View File

@ -1,3 +1,105 @@
##2015-04-14 - Supported Release 4.6.0
###Summary
Adds functions and function argument abilities, and improves compatibility with the new puppet parser
####Features
- MODULES-444: `concat()` can now take more than two arrays
- `basename()` added to have Ruby File.basename functionality
- `delete()` can now take an array of items to remove
- `prefix()` can now take a hash
- `upcase()` can now take a hash or array of upcaseable things
- `validate_absolute_path()` can now take an array
- `validate_cmd()` can now use % in the command to embed the validation file argument in the string
- MODULES-1473: deprecate `type()` function in favor of `type3x()`
- MODULES-1473: Add `type_of()` to give better time information on future parser
- Deprecate `private()` for `assert_private()` due to future parser
- Adds `ceiling()` to take the ceiling of a number
- Adds `fqdn_rand_string()` to generate random string based on fqdn
- Adds `pw_hash()` to generate password hashes
- Adds `validate_integer()`
- Adds `validate_numeric()` (like `validate_integer()` but also accepts floats)
####Bugfixes
- Fix seeding of `fqdn_rotate()`
- `ensure_resource()` is more verbose on debug mode
- Stricter argument checking for `dirname()`
- Fix `is_domain_name()` to better match RFC
- Fix `uriescape()` when called with array
- Fix `file_line` resource when using the `after` attribute with `match`
##2015-01-14 - Supported Release 4.5.1
###Summary
This release changes the temporary facter_dot_d cache locations outside of the /tmp directory due to a possible security vunerability. CVE-2015-1029
####Bugfixes
- Facter_dot_d cache will now be stored in puppet libdir instead of tmp
##2014-12-15 - Supported Release 4.5.0
###Summary
This release improves functionality of the member function and adds improved future parser support.
####Features
- MODULES-1329: Update member() to allow the variable to be an array.
- Sync .travis.yml, Gemfile, Rakefile, and CONTRIBUTING.md via modulesync
####Bugfixes
- Fix range() to work with numeric ranges with the future parser
- Accurately express SLES support in metadata.json (was missing 10SP4 and 12)
- Don't require `line` to match the `match` parameter
##2014-11-10 - Supported Release 4.4.0
###Summary
This release has an overhauled readme, new private manifest function, and fixes many future parser bugs.
####Features
- All new shiny README
- New `private()` function for making private manifests (yay!)
####Bugfixes
- Code reuse in `bool2num()` and `zip()`
- Fix many functions to handle `generate()` no longer returning a string on new puppets
- `concat()` no longer modifies the first argument (whoops)
- strict variable support for `getvar()`, `member()`, `values_at`, and `has_interface_with()`
- `to_bytes()` handles PB and EB now
- Fix `tempfile` ruby requirement for `validate_augeas()` and `validate_cmd()`
- Fix `validate_cmd()` for windows
- Correct `validate_string()` docs to reflect non-handling of `undef`
- Fix `file_line` matching on older rubies
##2014-07-15 - Supported Release 4.3.2
###Summary
This release merely updates metadata.json so the module can be uninstalled and
upgraded via the puppet module command.
##2014-07-14 - Supported Release 4.3.1
### Summary
This supported release updates the metadata.json to work around upgrade behavior of the PMT.
#### Bugfixes
- Synchronize metadata.json with PMT-generated metadata to pass checksums
##2014-06-27 - Supported Release 4.3.0
### Summary
This release is the first supported release of the stdlib 4 series. It remains
backwards-compatible with the stdlib 3 series. It adds two new functions, one bugfix, and many testing updates.
#### Features
- New `bool2str()` function
- New `camalcase()` function
#### Bugfixes
- Fix `has_interface_with()` when interfaces fact is nil
##2014-06-04 - Release 4.2.2
### Summary
This release adds PE3.3 support in the metadata and fixes a few tests.
## 2014-05-08 - Release - 4.2.1
### Summary
This release moves a stray symlink that can cause problems.

View File

@ -1,65 +1,220 @@
# How to contribute
Checklist (and a short version for the impatient)
=================================================
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.
* Commits:
## Getting Started
- Make commits of logical units.
* Make sure you have a [Jira account](http://tickets.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
- Check for unnecessary whitespace with "git diff --check" before
committing.
## Making Changes
- Commit using Unix line endings (check the settings around "crlf" in
git-config(1)).
* 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.
- Do not check in commented out code or unneeded files.
````
(#99999) Make the example in CONTRIBUTING imperative and concrete
- The first line of the commit message should be a short
description (50 characters is the soft limit, excluding ticket
number(s)), and should skip the full stop.
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.
- Associate the issue in the message. The first line should include
the issue number in the form "(#XXXX) Rest of message".
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.
````
- The body should provide a meaningful commit message, which:
* Make sure you have added the necessary tests for your changes.
* Run _all_ the tests to assure nothing else was accidentally broken.
- uses the imperative, present tense: "change", not "changed" or
"changes".
## Submitting Changes
- includes motivation for the change, and contrasts its
implementation with the previous behavior.
* 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 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
- Make sure that you have tests for the bug you are fixing, or
feature you are adding.
# Additional Resources
- Make sure the test suites passes after your commit:
`bundle exec rspec spec/acceptance` More information on [testing](#Testing) below
- When introducing a new feature, make sure it is properly
documented in the README.md
* Submission:
* Pre-requisites:
- Make sure you have a [GitHub account](https://github.com/join)
- [Create a ticket](https://tickets.puppetlabs.com/secure/CreateIssue!default.jspa), or [watch the ticket](https://tickets.puppetlabs.com/browse/) you are patching for.
* Preferred method:
- Fork the repository on GitHub.
- Push your changes to a topic branch in your fork of the
repository. (the format ticket/1234-short_description_of_change is
usually preferred for this project).
- Submit a pull request to the repository in the puppetlabs
organization.
The long version
================
1. Make separate commits for logically separate changes.
Please break your commits down into logically consistent units
which include new or changed tests relevant to the rest of the
change. The goal of doing this is to make the diff easier to
read for whoever is reviewing your code. In general, the easier
your diff is to read, the more likely someone will be happy to
review it and get it into the code base.
If you are going to refactor a piece of code, please do so as a
separate commit from your feature or bug fix changes.
We also really appreciate changes that include tests to make
sure the bug is not re-introduced, and that the feature is not
accidentally broken.
Describe the technical detail of the change(s). If your
description starts to get too long, that is a good sign that you
probably need to split up your commit into more finely grained
pieces.
Commits which plainly describe the things which help
reviewers check the patch and future developers understand the
code are much more likely to be merged in with a minimum of
bike-shedding or requested changes. Ideally, the commit message
would include information, and be in a form suitable for
inclusion in the release notes for the version of Puppet that
includes them.
Please also check that you are not introducing any trailing
whitespace or other "whitespace errors". You can do this by
running "git diff --check" on your changes before you commit.
2. Sending your patches
To submit your changes via a GitHub pull request, we _highly_
recommend that you have them on a topic branch, instead of
directly on "master".
It makes things much easier to keep track of, especially if
you decide to work on another thing before your first change
is merged in.
GitHub has some pretty good
[general documentation](http://help.github.com/) on using
their site. They also have documentation on
[creating pull requests](http://help.github.com/send-pull-requests/).
In general, after pushing your topic branch up to your
repository on GitHub, you can switch to the branch in the
GitHub UI and click "Pull Request" towards the top of the page
in order to open a pull request.
3. Update the related GitHub issue.
If there is a GitHub issue associated with the change you
submitted, then you should update the ticket to include the
location of your branch, along with any other commentary you
may wish to make.
Testing
=======
Getting Started
---------------
Our puppet modules provide [`Gemfile`](./Gemfile)s which can tell a ruby
package manager such as [bundler](http://bundler.io/) what Ruby packages,
or Gems, are required to build, develop, and test this software.
Please make sure you have [bundler installed](http://bundler.io/#getting-started)
on your system, then use it to install all dependencies needed for this project,
by running
```shell
% bundle install
Fetching gem metadata from https://rubygems.org/........
Fetching gem metadata from https://rubygems.org/..
Using rake (10.1.0)
Using builder (3.2.2)
-- 8><-- many more --><8 --
Using rspec-system-puppet (2.2.0)
Using serverspec (0.6.3)
Using rspec-system-serverspec (1.0.0)
Using bundler (1.3.5)
Your bundle is complete!
Use `bundle show [gemname]` to see where a bundled gem is installed.
```
NOTE some systems may require you to run this command with sudo.
If you already have those gems installed, make sure they are up-to-date:
```shell
% bundle update
```
With all dependencies in place and up-to-date we can now run the tests:
```shell
% rake spec
```
This will execute all the [rspec tests](http://rspec-puppet.com/) tests
under [spec/defines](./spec/defines), [spec/classes](./spec/classes),
and so on. rspec tests may have the same kind of dependencies as the
module they are testing. While the module defines in its [Modulefile](./Modulefile),
rspec tests define them in [.fixtures.yml](./fixtures.yml).
Some puppet modules also come with [beaker](https://github.com/puppetlabs/beaker)
tests. These tests spin up a virtual machine under
[VirtualBox](https://www.virtualbox.org/)) with, controlling it with
[Vagrant](http://www.vagrantup.com/) to actually simulate scripted test
scenarios. In order to run these, you will need both of those tools
installed on your system.
You can run them by issuing the following command
```shell
% rake spec_clean
% rspec spec/acceptance
```
This will now download a pre-fabricated image configured in the [default node-set](./spec/acceptance/nodesets/default.yml),
install puppet, copy this module and install its dependencies per [spec/spec_helper_acceptance.rb](./spec/spec_helper_acceptance.rb)
and then run all the tests under [spec/acceptance](./spec/acceptance).
Writing Tests
-------------
XXX getting started writing tests.
If you have commit access to the repository
===========================================
Even if you have commit access to the repository, you will still need to
go through the process above, and have someone else review and merge
in your changes. The rule is that all changes must be reviewed by a
developer on the project (that did not write the code) to ensure that
all changes go through a code review process.
Having someone other than the author of the topic branch recorded as
performing the merge is the record that they performed the code
review.
Additional Resources
====================
* [Getting additional help](http://puppetlabs.com/community/get-help)
* [Writing tests](http://projects.puppetlabs.com/projects/puppet/wiki/Development_Writing_Tests)
* [Patchwork](https://patchwork.puppetlabs.com)
* [More information on contributing](http://links.puppetlabs.com/contribute-to-puppet)
* [Bug tracker (Jira)](http://tickets.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

View File

@ -10,20 +10,38 @@ def location_for(place, fake_version = nil)
end
end
group :development, :test do
group :development, :unit_tests do
gem 'rake', '~> 10.1.0', :require => false
gem 'rspec', '~> 3.1.0', :require => false
gem 'rspec-puppet', :require => false
gem 'puppetlabs_spec_helper', :require => false
gem 'serverspec', :require => false
gem 'puppet-lint', :require => false
gem 'pry', :require => false
gem 'simplecov', :require => false
gem 'beaker', :require => false
gem 'beaker-rspec', :require => false
end
ENV['GEM_PUPPET_VERSION'] ||= ENV['PUPPET_GEM_VERSION']
puppetversion = ENV['GEM_PUPPET_VERSION']
beaker_version = ENV['BEAKER_VERSION']
beaker_rspec_version = ENV['BEAKER_RSPEC_VERSION']
group :system_tests do
if beaker_version
gem 'beaker', *location_for(beaker_version)
end
if beaker_rspec_version
gem 'beaker-rspec', *location_for(beaker_rspec_version)
else
gem 'beaker-rspec', :require => false
end
gem 'serverspec', :require => false
end
facterversion = ENV['GEM_FACTER_VERSION'] || ENV['FACTER_GEM_VERSION']
if facterversion
gem 'facter', *location_for(facterversion)
else
gem 'facter', :require => false
end
puppetversion = ENV['GEM_PUPPET_VERSION'] || ENV['PUPPET_GEM_VERSION']
if puppetversion
gem 'puppet', *location_for(puppetversion)
else

View File

@ -1,11 +0,0 @@
name 'puppetlabs-stdlib'
version '4.2.1'
source 'git://github.com/puppetlabs/puppetlabs-stdlib.git'
author 'puppetlabs'
license 'Apache 2.0'
summary 'Puppet Module Standard Library'
description 'Standard Library for Puppet Modules'
project_page 'https://github.com/puppetlabs/puppetlabs-stdlib'
## Add dependencies, if any:
# dependency 'username/name', '>= 1.2.0'

File diff suppressed because it is too large Load Diff

View File

@ -15,7 +15,7 @@
class Facter::Util::DotD
require 'yaml'
def initialize(dir="/etc/facts.d", cache_file="/tmp/facts_cache.yml")
def initialize(dir="/etc/facts.d", cache_file=File.join(Puppet[:libdir], "facts_dot_d.cache"))
@dir = dir
@cache_file = cache_file
@cache = nil
@ -23,7 +23,7 @@ class Facter::Util::DotD
end
def entries
Dir.entries(@dir).reject{|f| f =~ /^\.|\.ttl$/}.sort.map {|f| File.join(@dir, f) }
Dir.entries(@dir).reject { |f| f =~ /^\.|\.ttl$/ }.sort.map { |f| File.join(@dir, f) }
rescue
[]
end
@ -113,7 +113,7 @@ class Facter::Util::DotD
def cache_save!
cache = load_cache
File.open(@cache_file, "w", 0600) {|f| f.write(YAML.dump(cache)) }
File.open(@cache_file, "w", 0600) { |f| f.write(YAML.dump(cache)) }
rescue
end

View File

@ -0,0 +1,17 @@
# Returns the type when passed a value.
#
# @example how to compare values' types
# # compare the types of two values
# if type_of($first_value) != type_of($second_value) { fail("first_value and second_value are different types") }
# @example how to compare against an abstract type
# unless type_of($first_value) <= Numeric { fail("first_value must be Numeric") }
# unless type_of{$first_value) <= Collection[1] { fail("first_value must be an Array or Hash, and contain at least one element") }
#
# See the documentation for "The Puppet Type System" for more information about types.
# See the `assert_type()` function for flexible ways to assert the type of a value.
#
Puppet::Functions.create_function(:type_of) do
def type_of(value)
Puppet::Pops::Types::TypeCalculator.infer_set(value)
end
end

View File

@ -0,0 +1,29 @@
#
# assert_private.rb
#
module Puppet::Parser::Functions
newfunction(:assert_private, :doc => <<-'EOS'
Sets the current class or definition as private.
Calling the class or definition from outside the current module will fail.
EOS
) do |args|
raise(Puppet::ParseError, "assert_private(): Wrong number of arguments "+
"given (#{args.size}}) for 0 or 1)") if args.size > 1
scope = self
if scope.lookupvar('module_name') != scope.lookupvar('caller_module_name')
message = nil
if args[0] and args[0].is_a? String
message = args[0]
else
manifest_name = scope.source.name
manifest_type = scope.source.type
message = (manifest_type.to_s == 'hostclass') ? 'Class' : 'Definition'
message += " #{manifest_name} is private"
end
raise(Puppet::ParseError, message)
end
end
end

View File

@ -0,0 +1,34 @@
module Puppet::Parser::Functions
newfunction(:basename, :type => :rvalue, :doc => <<-EOS
Strips directory (and optional suffix) from a filename
EOS
) do |arguments|
if arguments.size < 1 then
raise(Puppet::ParseError, "basename(): No arguments given")
elsif arguments.size > 2 then
raise(Puppet::ParseError, "basename(): Too many arguments given (#{arguments.size})")
else
unless arguments[0].is_a?(String)
raise(Puppet::ParseError, 'basename(): Requires string as first argument')
end
if arguments.size == 1 then
rv = File.basename(arguments[0])
elsif arguments.size == 2 then
unless arguments[1].is_a?(String)
raise(Puppet::ParseError, 'basename(): Requires string as second argument')
end
rv = File.basename(arguments[0], arguments[1])
end
end
return rv
end
end
# vim: set ts=2 sw=2 et :

View File

@ -14,30 +14,7 @@ module Puppet::Parser::Functions
raise(Puppet::ParseError, "bool2num(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
klass = value.class
# We can have either true or false, or string which resembles boolean ...
unless [FalseClass, TrueClass, String].include?(klass)
raise(Puppet::ParseError, 'bool2num(): Requires either ' +
'boolean or string to work with')
end
if value.is_a?(String)
# We consider all the yes, no, y, n and so on too ...
value = case value
#
# This is how undef looks like in Puppet ...
# We yield 0 (or false if you wish) in this case.
#
when /^$/, '' then false # Empty string will be false ...
when /^(1|t|y|true|yes)$/ then true
when /^(0|f|n|false|no)$/ then false
when /^(undef|undefined)$/ then false # This is not likely to happen ...
else
raise(Puppet::ParseError, 'bool2num(): Unknown type of boolean given')
end
end
value = function_str2bool([arguments[0]])
# We have real boolean values as well ...
result = value ? 1 : 0

View File

@ -0,0 +1,27 @@
#
# bool2str.rb
#
module Puppet::Parser::Functions
newfunction(:bool2str, :type => :rvalue, :doc => <<-EOS
Converts a boolean to a string.
Requires a single boolean as an input.
EOS
) do |arguments|
raise(Puppet::ParseError, "bool2str(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
klass = value.class
# We can have either true or false, and nothing else
unless [FalseClass, TrueClass].include?(klass)
raise(Puppet::ParseError, 'bool2str(): Requires a boolean to work with')
end
return value.to_s
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,33 @@
#
# camelcase.rb
#
module Puppet::Parser::Functions
newfunction(:camelcase, :type => :rvalue, :doc => <<-EOS
Converts the case of a string or all strings in an array to camel case.
EOS
) do |arguments|
raise(Puppet::ParseError, "camelcase(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
klass = value.class
unless [Array, String].include?(klass)
raise(Puppet::ParseError, 'camelcase(): Requires either ' +
'array or string to work with')
end
if value.is_a?(Array)
# Numbers in Puppet are often string-encoded which is troublesome ...
result = value.collect { |i| i.is_a?(String) ? i.split('_').map{|e| e.capitalize}.join : i }
else
result = value.split('_').map{|e| e.capitalize}.join
end
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -13,9 +13,8 @@ module Puppet::Parser::Functions
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
klass = value.class
unless [Array, String].include?(klass)
unless value.is_a?(Array) || value.is_a?(String)
raise(Puppet::ParseError, 'capitalize(): Requires either ' +
'array or string to work with')
end

View File

@ -0,0 +1,25 @@
module Puppet::Parser::Functions
newfunction(:ceiling, :type => :rvalue, :doc => <<-EOS
Returns the smallest integer greater or equal to the argument.
Takes a single numeric value as an argument.
EOS
) do |arguments|
raise(Puppet::ParseError, "ceiling(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size != 1
begin
arg = Float(arguments[0])
rescue TypeError, ArgumentError => e
raise(Puppet::ParseError, "ceiling(): Wrong argument type " +
"given (#{arguments[0]} for Numeric)")
end
raise(Puppet::ParseError, "ceiling(): Wrong argument type " +
"given (#{arg.class} for Numeric)") if arg.is_a?(Numeric) == false
arg.ceil
end
end
# vim: set ts=2 sw=2 et :

View File

@ -14,9 +14,8 @@ module Puppet::Parser::Functions
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
klass = value.class
unless [Array, String].include?(klass)
unless value.is_a?(Array) || value.is_a?(String)
raise(Puppet::ParseError, 'chomp(): Requires either ' +
'array or string to work with')
end

View File

@ -16,9 +16,8 @@ module Puppet::Parser::Functions
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
klass = value.class
unless [Array, String].include?(klass)
unless value.is_a?(Array) || value.is_a?(String)
raise(Puppet::ParseError, 'chop(): Requires either an ' +
'array or string to work with')
end

View File

@ -4,34 +4,34 @@
module Puppet::Parser::Functions
newfunction(:concat, :type => :rvalue, :doc => <<-EOS
Appends the contents of array 2 onto array 1.
Appends the contents of multiple arrays into array 1.
*Example:*
concat(['1','2','3'],['4','5','6'])
concat(['1','2','3'],['4','5','6'],['7','8','9'])
Would result in:
['1','2','3','4','5','6']
['1','2','3','4','5','6','7','8','9']
EOS
) do |arguments|
# Check that 2 arguments have been given ...
# Check that more than 2 arguments have been given ...
raise(Puppet::ParseError, "concat(): Wrong number of arguments " +
"given (#{arguments.size} for 2)") if arguments.size != 2
"given (#{arguments.size} for < 2)") if arguments.size < 2
a = arguments[0]
b = arguments[1]
# Check that the first parameter is an array
unless a.is_a?(Array)
raise(Puppet::ParseError, 'concat(): Requires array to work with')
end
if b.is_a?(Array)
result = a.concat(b)
else
result = a << b
result = a
arguments.shift
arguments.each do |x|
result = result + Array(x)
end
return result

View File

@ -17,27 +17,30 @@ string, or key from a hash.
delete({'a'=>1,'b'=>2,'c'=>3}, 'b')
Would return: {'a'=>1,'c'=>3}
delete({'a'=>1,'b'=>2,'c'=>3}, ['b','c'])
Would return: {'a'=>1}
delete('abracadabra', 'bra')
Would return: 'acada'
EOS
EOS
) do |arguments|
if (arguments.size != 2) then
raise(Puppet::ParseError, "delete(): Wrong number of arguments "+
"given #{arguments.size} for 2.")
"given #{arguments.size} for 2.")
end
collection = arguments[0].dup
item = arguments[1]
case collection
when Array, Hash
collection.delete item
when String
collection.gsub! item, ''
else
raise(TypeError, "delete(): First argument must be an Array, " +
"String, or Hash. Given an argument of class #{collection.class}.")
Array(arguments[1]).each do |item|
case collection
when Array, Hash
collection.delete item
when String
collection.gsub! item, ''
else
raise(TypeError, "delete(): First argument must be an Array, " +
"String, or Hash. Given an argument of class #{collection.class}.")
end
end
collection
end

View File

@ -4,11 +4,17 @@ module Puppet::Parser::Functions
EOS
) do |arguments|
raise(Puppet::ParseError, "dirname(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
if arguments.size < 1 then
raise(Puppet::ParseError, "dirname(): No arguments given")
end
if arguments.size > 1 then
raise(Puppet::ParseError, "dirname(): Too many arguments given (#{arguments.size})")
end
unless arguments[0].is_a?(String)
raise(Puppet::ParseError, 'dirname(): Requires string as argument')
end
path = arguments[0]
return File.dirname(path)
return File.dirname(arguments[0])
end
end

View File

@ -12,9 +12,8 @@ Converts the case of a string or all strings in an array to lower case.
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
klass = value.class
unless [Array, String].include?(klass)
unless value.is_a?(Array) || value.is_a?(String)
raise(Puppet::ParseError, 'downcase(): Requires either ' +
'array or string to work with')
end

View File

@ -12,9 +12,8 @@ Returns true if the variable is empty.
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
klass = value.class
unless [Array, Hash, String].include?(klass)
unless value.is_a?(Array) || value.is_a?(Hash) || value.is_a?(String)
raise(Puppet::ParseError, 'empty(): Requires either ' +
'array, hash or string to work with')
end

View File

@ -36,8 +36,9 @@ ENDOFDOC
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")
Puppet.debug("Resource #{type}[#{item}] with params #{params} not created because it already exists")
else
Puppet.debug("Create new resource #{type}[#{item}] with params #{params}")
Puppet::Parser::Functions.function(:create_resources)
function_create_resources([type.capitalize, { item => params }])
end

View File

@ -0,0 +1,34 @@
Puppet::Parser::Functions::newfunction(
:fqdn_rand_string,
:arity => -2,
:type => :rvalue,
:doc => "Usage: `fqdn_rand_string(LENGTH, [CHARSET], [SEED])`. LENGTH is
required and must be a positive integer. CHARSET is optional and may be
`undef` or a string. SEED is optional and may be any number or string.
Generates a random string LENGTH characters long using the character set
provided by CHARSET, combining the `$fqdn` fact and the value of SEED for
repeatable randomness. (That is, each node will get a different random
string from this function, but a given node's result will be the same every
time unless its hostname changes.) Adding a SEED can be useful if you need
more than one unrelated string. CHARSET will default to alphanumeric if
`undef` or an empty string.") do |args|
raise(ArgumentError, "fqdn_rand_string(): wrong number of arguments (0 for 1)") if args.size == 0
Puppet::Parser::Functions.function('is_integer')
raise(ArgumentError, "fqdn_rand_base64(): first argument must be a positive integer") unless function_is_integer([args[0]]) and args[0].to_i > 0
raise(ArgumentError, "fqdn_rand_base64(): second argument must be undef or a string") unless args[1].nil? or args[1].is_a? String
Puppet::Parser::Functions.function('fqdn_rand')
length = args.shift.to_i
charset = args.shift.to_s.chars.to_a
charset = (0..9).map { |i| i.to_s } + ('A'..'Z').to_a + ('a'..'z').to_a if charset.empty?
rand_string = ''
for current in 1..length
rand_string << charset[function_fqdn_rand([charset.size, (args + [current.to_s]).join(':')]).to_i]
end
rand_string
end

View File

@ -12,10 +12,9 @@ Rotates an array a random number of times based on a nodes fqdn.
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
klass = value.class
require 'digest/md5'
unless [Array, String].include?(klass)
unless value.is_a?(Array) || value.is_a?(String)
raise(Puppet::ParseError, 'fqdn_rotate(): Requires either ' +
'array or string to work with')
end
@ -32,8 +31,20 @@ Rotates an array a random number of times based on a nodes fqdn.
elements = result.size
srand(Digest::MD5.hexdigest([lookupvar('::fqdn'),arguments].join(':')).hex)
rand(elements).times {
seed = Digest::MD5.hexdigest([lookupvar('::fqdn'),arguments].join(':')).hex
# deterministic_rand() was added in Puppet 3.2.0; reimplement if necessary
if Puppet::Util.respond_to?(:deterministic_rand)
offset = Puppet::Util.deterministic_rand(seed, elements).to_i
else
if defined?(Random) == 'constant' && Random.class == Class
offset = Random.new(seed).rand(elements)
else
srand(seed)
offset = rand(elements)
srand()
end
end
offset.times {
result.push result.shift
}

View File

@ -19,7 +19,10 @@ module Puppet::Parser::Functions
raise Puppet::ParseError, ("getvar(): wrong number of arguments (#{args.length}; must be 1)")
end
self.lookupvar("#{args[0]}")
begin
self.lookupvar("#{args[0]}")
rescue Puppet::ParseError # Eat the exception if strict_variables = true is set
end
end

View File

@ -25,7 +25,7 @@ has_interface_with("lo") => true
interfaces = lookupvar('interfaces')
# If we do not have any interfaces, then there are no requested attributes
return false if (interfaces == :undefined)
return false if (interfaces == :undefined || interfaces.nil?)
interfaces = interfaces.split(',')
@ -35,13 +35,29 @@ has_interface_with("lo") => true
kind, value = args
if lookupvar(kind) == value
# Bug with 3.7.1 - 3.7.3 when using future parser throws :undefined_variable
# https://tickets.puppetlabs.com/browse/PUP-3597
factval = nil
catch :undefined_variable do
factval = lookupvar(kind)
end
if factval == value
return true
end
result = false
interfaces.each do |iface|
if value == lookupvar("#{kind}_#{iface}")
iface.downcase!
factval = nil
begin
# Bug with 3.7.1 - 3.7.3 when using future parser throws :undefined_variable
# https://tickets.puppetlabs.com/browse/PUP-3597
catch :undefined_variable do
factval = lookupvar("#{kind}_#{iface}")
end
rescue Puppet::ParseError # Eat the exception if strict_variables = true is set
end
if value == factval
result = true
break
end

View File

@ -13,16 +13,16 @@ Returns true if the string passed to this function is a syntactically correct do
"given #{arguments.size} for 1")
end
domain = arguments[0]
# Only allow string types
return false unless arguments[0].is_a?(String)
domain = arguments[0].dup
# Limits (rfc1035, 3.1)
domain_max_length=255
label_min_length=1
label_max_length=63
# Only allow string types
return false unless domain.is_a?(String)
# Allow ".", it is the top level domain
return true if domain == '.'
@ -33,6 +33,10 @@ Returns true if the string passed to this function is a syntactically correct do
return false if domain.empty?
return false if domain.length > domain_max_length
# The top level domain must be alphabetic if there are multiple labels.
# See rfc1123, 2.1
return false if domain.include? '.' and not /\.[A-Za-z]+$/.match(domain)
# Check each label in the domain
labels = domain.split('.')
vlabels = labels.each do |label|

View File

@ -12,9 +12,8 @@ Strips leading spaces to the left of a string.
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
klass = value.class
unless [Array, String].include?(klass)
unless value.is_a?(Array) || value.is_a?(String)
raise(Puppet::ParseError, 'lstrip(): Requires either ' +
'array or string to work with')
end

View File

@ -8,6 +8,7 @@
module Puppet::Parser::Functions
newfunction(:member, :type => :rvalue, :doc => <<-EOS
This function determines if a variable is a member of an array.
The variable can be a string, fixnum, or array.
*Examples:*
@ -15,9 +16,17 @@ This function determines if a variable is a member of an array.
Would return: true
member(['a', 'b', 'c'], ['a', 'b'])
would return: true
member(['a','b'], 'c')
Would return: false
member(['a', 'b', 'c'], ['d', 'b'])
would return: false
EOS
) do |arguments|
@ -30,12 +39,21 @@ Would return: false
raise(Puppet::ParseError, 'member(): Requires array to work with')
end
item = arguments[1]
unless arguments[1].is_a? String or arguments[1].is_a? Fixnum or arguments[1].is_a? Array
raise(Puppet::ParseError, 'member(): Item to search for must be a string, fixnum, or array')
end
if arguments[1].is_a? String or arguments[1].is_a? Fixnum
item = Array(arguments[1])
else
item = arguments[1]
end
raise(Puppet::ParseError, 'member(): You must provide item ' +
'to search for within array given') if item.empty?
'to search for within array given') if item.respond_to?('empty?') && item.empty?
result = array.include?(item)
result = (item - array).empty?
return result
end

View File

@ -4,7 +4,7 @@
module Puppet::Parser::Functions
newfunction(:prefix, :type => :rvalue, :doc => <<-EOS
This function applies a prefix to all elements in an array.
This function applies a prefix to all elements in an array or a hash.
*Examples:*
@ -18,10 +18,10 @@ Will return: ['pa','pb','pc']
raise(Puppet::ParseError, "prefix(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
array = arguments[0]
enumerable = arguments[0]
unless array.is_a?(Array)
raise Puppet::ParseError, "prefix(): expected first argument to be an Array, got #{array.inspect}"
unless enumerable.is_a?(Array) or enumerable.is_a?(Hash)
raise Puppet::ParseError, "prefix(): expected first argument to be an Array or a Hash, got #{enumerable.inspect}"
end
prefix = arguments[1] if arguments[1]
@ -32,10 +32,17 @@ Will return: ['pa','pb','pc']
end
end
# Turn everything into string same as join would do ...
result = array.collect do |i|
i = i.to_s
prefix ? prefix + i : i
if enumerable.is_a?(Array)
# Turn everything into string same as join would do ...
result = enumerable.collect do |i|
i = i.to_s
prefix ? prefix + i : i
end
else
result = Hash[enumerable.map do |k,v|
k = k.to_s
[ prefix ? prefix + k : k, v ]
end]
end
return result

View File

@ -0,0 +1,17 @@
#
# private.rb
#
module Puppet::Parser::Functions
newfunction(:private, :doc => <<-'EOS'
DEPRECATED: Sets the current class or definition as private.
Calling the class or definition from outside the current module will fail.
EOS
) do |args|
warning("private() DEPRECATED: This function will cease to function on Puppet 4; please use assert_private() before upgrading to puppet 4 for backwards-compatibility, or migrate to the new parser's typing system.")
if !Puppet::Parser::Functions.autoloader.loaded?(:assert_private)
Puppet::Parser::Functions.autoloader.load(:assert_private)
end
function_assert_private([(args[0] unless args.size < 1)])
end
end

View File

@ -0,0 +1,56 @@
Puppet::Parser::Functions::newfunction(
:pw_hash,
:type => :rvalue,
:arity => 3,
:doc => "Hashes a password using the crypt function. Provides a hash
usable on most POSIX systems.
The first argument to this function is the password to hash. If it is
undef or an empty string, this function returns undef.
The second argument to this function is which type of hash to use. It
will be converted into the appropriate crypt(3) hash specifier. Valid
hash types are:
|Hash type |Specifier|
|---------------------|---------|
|MD5 |1 |
|SHA-256 |5 |
|SHA-512 (recommended)|6 |
The third argument to this function is the salt to use.
Note: this uses the Puppet Master's implementation of crypt(3). If your
environment contains several different operating systems, ensure that they
are compatible before using this function.") do |args|
raise ArgumentError, "pw_hash(): wrong number of arguments (#{args.size} for 3)" if args.size != 3
raise ArgumentError, "pw_hash(): first argument must be a string" unless args[0].is_a? String or args[0].nil?
raise ArgumentError, "pw_hash(): second argument must be a string" unless args[1].is_a? String
hashes = { 'md5' => '1',
'sha-256' => '5',
'sha-512' => '6' }
hash_type = hashes[args[1].downcase]
raise ArgumentError, "pw_hash(): #{args[1]} is not a valid hash type" if hash_type.nil?
raise ArgumentError, "pw_hash(): third argument must be a string" unless args[2].is_a? String
raise ArgumentError, "pw_hash(): third argument must not be empty" if args[2].empty?
raise ArgumentError, "pw_hash(): characters in salt must be in the set [a-zA-Z0-9./]" unless args[2].match(/\A[a-zA-Z0-9.\/]+\z/)
password = args[0]
return nil if password.nil? or password.empty?
# handle weak implementations of String#crypt
if 'test'.crypt('$1$1') != '$1$1$Bp8CU9Oujr9SSEw53WV6G.'
# JRuby < 1.7.17
if RUBY_PLATFORM == 'java'
# override String#crypt for password variable
def password.crypt(salt)
# puppetserver bundles Apache Commons Codec
org.apache.commons.codec.digest.Crypt.crypt(self.to_java_bytes, salt)
end
else
# MS Windows and other systems that don't support enhanced salts
raise Puppet::ParseError, 'system does not support enhanced salts'
end
end
password.crypt("$#{hash_type}$#{args[2]}")
end

View File

@ -65,21 +65,21 @@ Will return: [0,2,4,6,8]
end
end
# Check whether we have integer value if so then make it so ...
if start.match(/^\d+$/)
start = start.to_i
stop = stop.to_i
else
start = start.to_s
stop = stop.to_s
end
# Check whether we have integer value if so then make it so ...
if start.to_s.match(/^\d+$/)
start = start.to_i
stop = stop.to_i
else
start = start.to_s
stop = stop.to_s
end
range = case type
when /^(\.\.|\-)$/ then (start .. stop)
when /^(\.\.\.)$/ then (start ... stop) # Exclusive of last element ...
end
range = case type
when /^(\.\.|\-)$/ then (start .. stop)
when /^(\.\.\.)$/ then (start ... stop) # Exclusive of last element ...
end
result = range.step(step).collect { |i| i } # Get them all ... Pokemon ...
result = range.step(step).collect { |i| i } # Get them all ... Pokemon ...
return result
end

View File

@ -12,9 +12,8 @@ Reverses the order of a string or array.
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
klass = value.class
unless [Array, String].include?(klass)
unless value.is_a?(Array) || value.is_a?(String)
raise(Puppet::ParseError, 'reverse(): Requires either ' +
'array or string to work with')
end

View File

@ -12,9 +12,8 @@ Strips leading spaces to the right of the string.
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
klass = value.class
unless [Array, String].include?(klass)
unless value.is_a?(Array) || value.is_a?(String)
raise(Puppet::ParseError, 'rstrip(): Requires either ' +
'array or string to work with')
end

View File

@ -12,9 +12,8 @@ Randomizes the order of a string or array elements.
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
klass = value.class
unless [Array, String].include?(klass)
unless value.is_a?(Array) || value.is_a?(String)
raise(Puppet::ParseError, 'shuffle(): Requires either ' +
'array or string to work with')
end

View File

@ -19,9 +19,8 @@ Would result in: "aaa"
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
klass = value.class
unless [Array, String].include?(klass)
unless value.is_a?(Array) || value.is_a?(String)
raise(Puppet::ParseError, 'strip(): Requires either ' +
'array or string to work with')
end

View File

@ -18,9 +18,8 @@ Would result in: "AbCd"
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
klass = value.class
unless [Array, String].include?(klass)
unless value.is_a?(Array) || value.is_a?(String)
raise(Puppet::ParseError, 'swapcase(): Requires either ' +
'array or string to work with')
end

View File

@ -2,6 +2,8 @@ module Puppet::Parser::Functions
newfunction(:to_bytes, :type => :rvalue, :doc => <<-EOS
Converts the argument into bytes, for example 4 kB becomes 4096.
Takes a single string value as an argument.
These conversions reflect a layperson's understanding of
1 MB = 1024 KB, when in fact 1 MB = 1000 KB, and 1 MiB = 1024 KiB.
EOS
) do |arguments|
@ -21,7 +23,8 @@ module Puppet::Parser::Functions
when 'M' then return (value*(1<<20)).to_i
when 'G' then return (value*(1<<30)).to_i
when 'T' then return (value*(1<<40)).to_i
when 'E' then return (value*(1<<50)).to_i
when 'P' then return (value*(1<<50)).to_i
when 'E' then return (value*(1<<60)).to_i
else raise Puppet::ParseError, "to_bytes(): Unknown prefix #{prefix}"
end
end

View File

@ -4,46 +4,15 @@
module Puppet::Parser::Functions
newfunction(:type, :type => :rvalue, :doc => <<-EOS
Returns the type when passed a variable. Type can be one of:
* string
* array
* hash
* float
* integer
* boolean
DEPRECATED: This function will cease to function on Puppet 4; please use type3x() before upgrading to puppet 4 for backwards-compatibility, or migrate to the new parser's typing system.
EOS
) do |arguments|
) do |args|
raise(Puppet::ParseError, "type(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
klass = value.class
if not [TrueClass, FalseClass, Array, Bignum, Fixnum, Float, Hash, String].include?(klass)
raise(Puppet::ParseError, 'type(): Unknown type')
warning("type() DEPRECATED: This function will cease to function on Puppet 4; please use type3x() before upgrading to puppet 4 for backwards-compatibility, or migrate to the new parser's typing system.")
if ! Puppet::Parser::Functions.autoloader.loaded?(:type3x)
Puppet::Parser::Functions.autoloader.load(:type3x)
end
klass = klass.to_s # Ugly ...
# We note that Integer is the parent to Bignum and Fixnum ...
result = case klass
when /^(?:Big|Fix)num$/ then 'integer'
when /^(?:True|False)Class$/ then 'boolean'
else klass
end
if result == "String" then
if value == value.to_i.to_s then
result = "Integer"
elsif value == value.to_f.to_s then
result = "Float"
end
end
return result.downcase
function_type3x(args + [false])
end
end

View File

@ -0,0 +1,51 @@
#
# type3x.rb
#
module Puppet::Parser::Functions
newfunction(:type3x, :type => :rvalue, :doc => <<-EOS
DEPRECATED: This function will be removed when puppet 3 support is dropped; please migrate to the new parser's typing system.
Returns the type when passed a value. Type can be one of:
* string
* array
* hash
* float
* integer
* boolean
EOS
) do |args|
raise(Puppet::ParseError, "type3x(): Wrong number of arguments " +
"given (#{args.size} for 1)") if args.size < 1
value = args[0]
klass = value.class
if not [TrueClass, FalseClass, Array, Bignum, Fixnum, Float, Hash, String].include?(klass)
raise(Puppet::ParseError, 'type3x(): Unknown type')
end
klass = klass.to_s # Ugly ...
# We note that Integer is the parent to Bignum and Fixnum ...
result = case klass
when /^(?:Big|Fix)num$/ then 'integer'
when /^(?:True|False)Class$/ then 'boolean'
else klass
end
if result == "String" then
if value == value.to_i.to_s then
result = "Integer"
elsif value == value.to_f.to_s then
result = "Float"
end
end
return result.downcase
end
end
# vim: set ts=2 sw=2 et :

View File

@ -28,9 +28,8 @@ This returns:
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
klass = value.class
unless [Array, String].include?(klass)
unless value.is_a?(Array) || value.is_a?(String)
raise(Puppet::ParseError, 'unique(): Requires either ' +
'array or string to work with')
end

View File

@ -13,23 +13,27 @@ Converts a string or an array of strings to uppercase.
Will return:
ASDF
EOS
EOS
) do |arguments|
raise(Puppet::ParseError, "upcase(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
"given (#{arguments.size} for 1)") if arguments.size != 1
value = arguments[0]
klass = value.class
unless [Array, String].include?(klass)
raise(Puppet::ParseError, 'upcase(): Requires either ' +
'array or string to work with')
unless value.is_a?(Array) || value.is_a?(Hash) || value.respond_to?(:upcase)
raise(Puppet::ParseError, 'upcase(): Requires an ' +
'array, hash or object that responds to upcase in order to work')
end
if value.is_a?(Array)
# Numbers in Puppet are often string-encoded which is troublesome ...
result = value.collect { |i| i.is_a?(String) ? i.upcase : i }
result = value.collect { |i| function_upcase([i]) }
elsif value.is_a?(Hash)
result = {}
value.each_pair do |k, v|
result[function_upcase([k])] = function_upcase([v])
end
else
result = value.upcase
end

View File

@ -14,16 +14,15 @@ module Puppet::Parser::Functions
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
klass = value.class
unless [Array, String].include?(klass)
unless value.is_a?(Array) || value.is_a?(String)
raise(Puppet::ParseError, 'uriescape(): Requires either ' +
'array or string to work with')
end
if value.is_a?(Array)
# Numbers in Puppet are often string-encoded which is troublesome ...
result = value.collect { |i| i.is_a?(String) ? URI.escape(i,unsafe) : i }
result = value.collect { |i| i.is_a?(String) ? URI.escape(i) : i }
else
result = URI.escape(value)
end

View File

@ -5,15 +5,20 @@ module Puppet::Parser::Functions
The following values will pass:
$my_path = "C:/Program Files (x86)/Puppet Labs/Puppet"
$my_path = 'C:/Program Files (x86)/Puppet Labs/Puppet'
validate_absolute_path($my_path)
$my_path2 = "/var/lib/puppet"
$my_path2 = '/var/lib/puppet'
validate_absolute_path($my_path2)
$my_path3 = ['C:/Program Files (x86)/Puppet Labs/Puppet','C:/Program Files/Puppet Labs/Puppet']
validate_absolute_path($my_path3)
$my_path4 = ['/var/lib/puppet','/usr/share/puppet']
validate_absolute_path($my_path4)
The following values will fail, causing compilation to abort:
validate_absolute_path(true)
validate_absolute_path('../var/lib/puppet')
validate_absolute_path('var/lib/puppet')
validate_absolute_path([ 'var/lib/puppet', '/var/foo' ])
validate_absolute_path([ '/var/lib/puppet', 'var/foo' ])
$undefined = undef
@ -28,28 +33,36 @@ module Puppet::Parser::Functions
end
args.each do |arg|
# This logic was borrowed from
# [lib/puppet/file_serving/base.rb](https://github.com/puppetlabs/puppet/blob/master/lib/puppet/file_serving/base.rb)
# Puppet 2.7 and beyond will have Puppet::Util.absolute_path? Fall back to a back-ported implementation otherwise.
if Puppet::Util.respond_to?(:absolute_path?) then
unless Puppet::Util.absolute_path?(arg, :posix) or Puppet::Util.absolute_path?(arg, :windows)
raise Puppet::ParseError, ("#{arg.inspect} is not an absolute path.")
# put arg to candidate var to be able to replace it
candidates = arg
# if arg is just a string with a path to test, convert it to an array
# to avoid test code duplication
unless arg.is_a?(Array) then
candidates = Array.new(1,arg)
end
# iterate over all pathes within the candidates array
candidates.each do |path|
# This logic was borrowed from
# [lib/puppet/file_serving/base.rb](https://github.com/puppetlabs/puppet/blob/master/lib/puppet/file_serving/base.rb)
# Puppet 2.7 and beyond will have Puppet::Util.absolute_path? Fall back to a back-ported implementation otherwise.
if Puppet::Util.respond_to?(:absolute_path?) then
unless Puppet::Util.absolute_path?(path, :posix) or Puppet::Util.absolute_path?(path, :windows)
raise Puppet::ParseError, ("#{path.inspect} is not an absolute path.")
end
else
# This code back-ported from 2.7.x's lib/puppet/util.rb Puppet::Util.absolute_path?
# Determine in a platform-specific way whether a path is absolute. This
# defaults to the local platform if none is specified.
# Escape once for the string literal, and once for the regex.
slash = '[\\\\/]'
name = '[^\\\\/]+'
regexes = {
:windows => %r!^(([A-Z]:#{slash})|(#{slash}#{slash}#{name}#{slash}#{name})|(#{slash}#{slash}\?#{slash}#{name}))!i,
:posix => %r!^/!,
}
rval = (!!(path =~ regexes[:posix])) || (!!(path =~ regexes[:windows]))
rval or raise Puppet::ParseError, ("#{path.inspect} is not an absolute path.")
end
else
# This code back-ported from 2.7.x's lib/puppet/util.rb Puppet::Util.absolute_path?
# Determine in a platform-specific way whether a path is absolute. This
# defaults to the local platform if none is specified.
# Escape once for the string literal, and once for the regex.
slash = '[\\\\/]'
name = '[^\\\\/]+'
regexes = {
:windows => %r!^(([A-Z]:#{slash})|(#{slash}#{slash}#{name}#{slash}#{name})|(#{slash}#{slash}\?#{slash}#{name}))!i,
:posix => %r!^/!,
}
rval = (!!(arg =~ regexes[:posix])) || (!!(arg =~ regexes[:windows]))
rval or raise Puppet::ParseError, ("#{arg.inspect} is not an absolute path.")
end
end
end

View File

@ -1,3 +1,5 @@
require 'tempfile'
module Puppet::Parser::Functions
newfunction(:validate_augeas, :doc => <<-'ENDHEREDOC') do |args|
Perform validation of a string using an Augeas lens

View File

@ -1,13 +1,14 @@
require 'puppet/util/execution'
require 'tempfile'
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.
taking a % as a placeholder for the file path (will default to the end).
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.
@ -16,8 +17,12 @@ module Puppet::Parser::Functions
Example:
# Defaults to end of path
validate_cmd($sudoerscontent, '/usr/sbin/visudo -c -f', 'Visudo failed to validate sudoers content')
# % as file location
validate_cmd($haproxycontent, '/usr/sbin/haproxy -f % -c', 'Haproxy failed to validate config 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)")
@ -33,14 +38,24 @@ module Puppet::Parser::Functions
begin
tmpfile.write(content)
tmpfile.close
if Puppet::Util::Execution.respond_to?('execute')
Puppet::Util::Execution.execute("#{checkscript} #{tmpfile.path}")
if checkscript =~ /\s%(\s|$)/
check_with_correct_location = checkscript.gsub(/%/,tmpfile.path)
else
Puppet::Util.execute("#{checkscript} #{tmpfile.path}")
check_with_correct_location = "#{checkscript} #{tmpfile.path}"
end
if Puppet::Util::Execution.respond_to?('execute')
Puppet::Util::Execution.execute(check_with_correct_location)
else
Puppet::Util.execute(check_with_correct_location)
end
rescue Puppet::ExecutionFailure => detail
msg += "\n#{detail}"
raise Puppet::ParseError, msg
rescue Exception => detail
msg += "\n#{detail.class.name} #{detail}"
raise Puppet::ParseError, msg
ensure
tmpfile.unlink
end

View File

@ -0,0 +1,131 @@
module Puppet::Parser::Functions
newfunction(:validate_integer, :doc => <<-'ENDHEREDOC') do |args|
Validate that the first argument is an integer (or an array of integers). Abort catalog compilation if any of the checks fail.
The second argument is optional and passes a maximum. (All elements of) the first argument has to be less or equal to this max.
The third argument is optional and passes a minimum. (All elements of) the first argument has to be greater or equal to this min.
If, and only if, a minimum is given, the second argument may be an empty string or undef, which will be handled to just check
if (all elements of) the first argument are greater or equal to the given minimum.
It will fail if the first argument is not an integer or array of integers, and if arg 2 and arg 3 are not convertable to an integer.
The following values will pass:
validate_integer(1)
validate_integer(1, 2)
validate_integer(1, 1)
validate_integer(1, 2, 0)
validate_integer(2, 2, 2)
validate_integer(2, '', 0)
validate_integer(2, undef, 0)
$foo = undef
validate_integer(2, $foo, 0)
validate_integer([1,2,3,4,5], 6)
validate_integer([1,2,3,4,5], 6, 0)
Plus all of the above, but any combination of values passed as strings ('1' or "1").
Plus all of the above, but with (correct) combinations of negative integer values.
The following values will not:
validate_integer(true)
validate_integer(false)
validate_integer(7.0)
validate_integer({ 1 => 2 })
$foo = undef
validate_integer($foo)
validate_integer($foobaridontexist)
validate_integer(1, 0)
validate_integer(1, true)
validate_integer(1, '')
validate_integer(1, undef)
validate_integer(1, , 0)
validate_integer(1, 2, 3)
validate_integer(1, 3, 2)
validate_integer(1, 3, true)
Plus all of the above, but any combination of values passed as strings ('false' or "false").
Plus all of the above, but with incorrect combinations of negative integer values.
Plus all of the above, but with non-integer crap in arrays or maximum / minimum argument.
ENDHEREDOC
# tell the user we need at least one, and optionally up to two other parameters
raise Puppet::ParseError, "validate_integer(): Wrong number of arguments; must be 1, 2 or 3, got #{args.length}" unless args.length > 0 and args.length < 4
input, max, min = *args
# check maximum parameter
if args.length > 1
max = max.to_s
# allow max to be empty (or undefined) if we have a minimum set
if args.length > 2 and max == ''
max = nil
else
begin
max = Integer(max)
rescue TypeError, ArgumentError
raise Puppet::ParseError, "validate_integer(): Expected second argument to be unset or an Integer, got #{max}:#{max.class}"
end
end
else
max = nil
end
# check minimum parameter
if args.length > 2
begin
min = Integer(min.to_s)
rescue TypeError, ArgumentError
raise Puppet::ParseError, "validate_integer(): Expected third argument to be unset or an Integer, got #{min}:#{min.class}"
end
else
min = nil
end
# ensure that min < max
if min and max and min > max
raise Puppet::ParseError, "validate_integer(): Expected second argument to be larger than third argument, got #{max} < #{min}"
end
# create lamba validator function
validator = lambda do |num|
# check input < max
if max and num > max
raise Puppet::ParseError, "validate_integer(): Expected #{input.inspect} to be smaller or equal to #{max}, got #{input.inspect}."
end
# check input > min (this will only be checked if no exception has been raised before)
if min and num < min
raise Puppet::ParseError, "validate_integer(): Expected #{input.inspect} to be greater or equal to #{min}, got #{input.inspect}."
end
end
# if this is an array, handle it.
case input
when Array
# check every element of the array
input.each_with_index do |arg, pos|
begin
arg = Integer(arg.to_s)
validator.call(arg)
rescue TypeError, ArgumentError
raise Puppet::ParseError, "validate_integer(): Expected element at array position #{pos} to be an Integer, got #{arg.class}"
end
end
# for the sake of compatibility with ruby 1.8, we need extra handling of hashes
when Hash
raise Puppet::ParseError, "validate_integer(): Expected first argument to be an Integer or Array, got #{input.class}"
# check the input. this will also fail any stuff other than pure, shiny integers
else
begin
input = Integer(input.to_s)
validator.call(input)
rescue TypeError, ArgumentError
raise Puppet::ParseError, "validate_integer(): Expected first argument to be an Integer or Array, got #{input.class}"
end
end
end
end

View File

@ -0,0 +1,93 @@
module Puppet::Parser::Functions
newfunction(:validate_numeric, :doc => <<-'ENDHEREDOC') do |args|
Validate that the first argument is a numeric value (or an array of numeric values). Abort catalog compilation if any of the checks fail.
The second argument is optional and passes a maximum. (All elements of) the first argument has to be less or equal to this max.
The third argument is optional and passes a minimum. (All elements of) the first argument has to be greater or equal to this min.
If, and only if, a minimum is given, the second argument may be an empty string or undef, which will be handled to just check
if (all elements of) the first argument are greater or equal to the given minimum.
It will fail if the first argument is not a numeric (Integer or Float) or array of numerics, and if arg 2 and arg 3 are not convertable to a numeric.
For passing and failing usage, see `validate_integer()`. It is all the same for validate_numeric, yet now floating point values are allowed, too.
ENDHEREDOC
# tell the user we need at least one, and optionally up to two other parameters
raise Puppet::ParseError, "validate_numeric(): Wrong number of arguments; must be 1, 2 or 3, got #{args.length}" unless args.length > 0 and args.length < 4
input, max, min = *args
# check maximum parameter
if args.length > 1
max = max.to_s
# allow max to be empty (or undefined) if we have a minimum set
if args.length > 2 and max == ''
max = nil
else
begin
max = Float(max)
rescue TypeError, ArgumentError
raise Puppet::ParseError, "validate_numeric(): Expected second argument to be unset or a Numeric, got #{max}:#{max.class}"
end
end
else
max = nil
end
# check minimum parameter
if args.length > 2
begin
min = Float(min.to_s)
rescue TypeError, ArgumentError
raise Puppet::ParseError, "validate_numeric(): Expected third argument to be unset or a Numeric, got #{min}:#{min.class}"
end
else
min = nil
end
# ensure that min < max
if min and max and min > max
raise Puppet::ParseError, "validate_numeric(): Expected second argument to be larger than third argument, got #{max} < #{min}"
end
# create lamba validator function
validator = lambda do |num|
# check input < max
if max and num > max
raise Puppet::ParseError, "validate_numeric(): Expected #{input.inspect} to be smaller or equal to #{max}, got #{input.inspect}."
end
# check input > min (this will only be checked if no exception has been raised before)
if min and num < min
raise Puppet::ParseError, "validate_numeric(): Expected #{input.inspect} to be greater or equal to #{min}, got #{input.inspect}."
end
end
# if this is an array, handle it.
case input
when Array
# check every element of the array
input.each_with_index do |arg, pos|
begin
arg = Float(arg.to_s)
validator.call(arg)
rescue TypeError, ArgumentError
raise Puppet::ParseError, "validate_numeric(): Expected element at array position #{pos} to be a Numeric, got #{arg.class}"
end
end
# for the sake of compatibility with ruby 1.8, we need extra handling of hashes
when Hash
raise Puppet::ParseError, "validate_integer(): Expected first argument to be a Numeric or Array, got #{input.class}"
# check the input. this will also fail any stuff other than pure, shiny integers
else
begin
input = Float(input.to_s)
validator.call(input)
rescue TypeError, ArgumentError
raise Puppet::ParseError, "validate_numeric(): Expected first argument to be a Numeric or Array, got #{input.class}"
end
end
end
end

View File

@ -13,9 +13,14 @@ module Puppet::Parser::Functions
validate_string(true)
validate_string([ 'some', 'array' ])
$undefined = undef
validate_string($undefined)
Note: validate_string(undef) will not fail in this version of the
functions API (incl. current and future parser). Instead, use:
if $var == undef {
fail('...')
}
ENDHEREDOC
unless args.length > 0 then

View File

@ -49,6 +49,7 @@ Would return ['a','c','d'].
indices_list = []
indices.each do |i|
i = i.to_s
if m = i.match(/^(\d+)(\.\.\.?|\-)(\d+)$/)
start = m[1].to_i
stop = m[3].to_i

View File

@ -27,33 +27,7 @@ Would result in:
raise(Puppet::ParseError, 'zip(): Requires array to work with')
end
flatten = arguments[2] if arguments[2]
if flatten
klass = flatten.class
# We can have either true or false, or string which resembles boolean ...
unless [FalseClass, TrueClass, String].include?(klass)
raise(Puppet::ParseError, 'zip(): Requires either ' +
'boolean or string to work with')
end
if flatten.is_a?(String)
# We consider all the yes, no, y, n and so on too ...
flatten = case flatten
#
# This is how undef looks like in Puppet ...
# We yield false in this case.
#
when /^$/, '' then false # Empty string will be false ...
when /^(1|t|y|true|yes)$/ then true
when /^(0|f|n|false|no)$/ then false
when /^(undef|undefined)$/ then false # This is not likely to happen ...
else
raise(Puppet::ParseError, 'zip(): Unknown type of boolean given')
end
end
end
flatten = function_str2bool([arguments[2]]) if arguments[2]
result = a.zip(b)
result = flatten ? result.flatten : result

View File

@ -34,30 +34,33 @@ 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) }.size
regex_after = resource[:after] ? Regexp.new(resource[:after]) : nil
match_count = count_matches(regex)
if match_count > 1 && resource[:multiple].to_s != 'true'
raise Puppet::Error, "More than one line in file '#{resource[:path]}' matches pattern '#{resource[:match]}'"
end
if (match_count == 0) and resource[:after]
handle_create_with_after
else
File.open(resource[:path], 'w') do |fh|
lines.each do |l|
fh.puts(regex.match(l) ? resource[:line] : l)
end
if (match_count == 0)
fh.puts(resource[:line])
File.open(resource[:path], 'w') do |fh|
lines.each do |l|
fh.puts(regex.match(l) ? resource[:line] : l)
if (match_count == 0 and regex_after)
if regex_after.match(l)
fh.puts(resource[:line])
match_count += 1 #Increment match_count to indicate that the new line has been inserted.
end
end
end
if (match_count == 0)
fh.puts(resource[:line])
end
end
end
def handle_create_with_after
regex = Regexp.new(resource[:after])
count = lines.count {|l| l.match(regex)}
count = count_matches(regex)
case count
when 1 # find the line to put our line after
File.open(resource[:path], 'w') do |fh|
@ -75,12 +78,19 @@ Puppet::Type.type(:file_line).provide(:ruby) do
end
end
def count_matches(regex)
lines.select{|l| l.match(regex)}.size
end
##
# append the line to the file.
#
# @api private
def append_line
File.open(resource[:path], 'a') do |fh|
File.open(resource[:path], 'w') do |fh|
lines.each do |l|
fh.puts(l)
end
fh.puts resource[:line]
end
end

View File

@ -3,9 +3,9 @@ Puppet::Type.newtype(:file_line) do
desc <<-EOT
Ensures that a given line is contained within a file. The implementation
matches the full line, including whitespace at the beginning and end. If
the line is not contained in the given file, Puppet will add the line to
ensure the desired state. Multiple resources may be declared to manage
multiple lines in the same file.
the line is not contained in the given file, Puppet will append the line to
the end of the file to ensure the desired state. Multiple resources may
be declared to manage multiple lines in the same file.
Example:
@ -13,6 +13,7 @@ Puppet::Type.newtype(:file_line) do
path => '/etc/sudoers',
line => '%sudo ALL=(ALL) ALL',
}
file_line { 'sudo_rule_nopw':
path => '/etc/sudoers',
line => '%sudonopw ALL=(ALL) NOPASSWD: ALL',
@ -21,6 +22,21 @@ Puppet::Type.newtype(:file_line) do
In this example, Puppet will ensure both of the specified lines are
contained in the file /etc/sudoers.
Match Example:
file_line { 'bashrc_proxy':
ensure => present,
path => '/etc/bashrc',
line => 'export HTTP_PROXY=http://squid.puppetlabs.vm:3128',
match => '^export\ HTTP_PROXY\=',
}
In this code example match will look for a line beginning with export
followed by HTTP_PROXY and replace it with the value in line.
**Autorequires:** If Puppet is managing the file that will contain the line
being managed, the file_line resource will autorequire that file.
EOT
ensurable do
@ -33,12 +49,15 @@ Puppet::Type.newtype(:file_line) do
end
newparam(:match) do
desc 'An optional regular expression to run against existing lines in the file;\n' +
'if a match is found, we replace that line rather than adding a new line.'
desc 'An optional ruby regular expression to run against existing lines in the file.' +
' If a match is found, we replace that line rather than adding a new line.' +
' A regex comparisson is performed against the line value and if it does not' +
' match an exception will be raised. '
end
newparam(:multiple) do
desc 'An optional value to determine if match can change multiple lines.'
desc 'An optional value to determine if match can change multiple lines.' +
' If set to false, an exception will be raised if more than one line matches'
newvalues(true, false)
end
@ -47,7 +66,7 @@ Puppet::Type.newtype(:file_line) do
end
newparam(:line) do
desc 'The line to be appended to the file located by the path parameter.'
desc 'The line to be appended to the file or used to replace matches found by the match attribute.'
end
newparam(:path) do
@ -68,12 +87,5 @@ Puppet::Type.newtype(:file_line) do
unless self[:line] and self[:path]
raise(Puppet::Error, "Both line and path are required attributes")
end
if (self[:match])
unless Regexp.new(self[:match]).match(self[:line])
raise(Puppet::Error, "When providing a 'match' parameter, the value must be a regex that matches against the value of your 'line' parameter")
end
end
end
end

View File

@ -0,0 +1,113 @@
{
"name": "puppetlabs-stdlib",
"version": "4.6.0",
"author": "puppetlabs",
"summary": "Standard library of resources for Puppet modules.",
"license": "Apache-2.0",
"source": "https://github.com/puppetlabs/puppetlabs-stdlib",
"project_page": "https://github.com/puppetlabs/puppetlabs-stdlib",
"issues_url": "https://tickets.puppetlabs.com/browse/MODULES",
"operatingsystem_support": [
{
"operatingsystem": "RedHat",
"operatingsystemrelease": [
"4",
"5",
"6",
"7"
]
},
{
"operatingsystem": "CentOS",
"operatingsystemrelease": [
"4",
"5",
"6",
"7"
]
},
{
"operatingsystem": "OracleLinux",
"operatingsystemrelease": [
"4",
"5",
"6",
"7"
]
},
{
"operatingsystem": "Scientific",
"operatingsystemrelease": [
"4",
"5",
"6",
"7"
]
},
{
"operatingsystem": "SLES",
"operatingsystemrelease": [
"10 SP4",
"11 SP1",
"12"
]
},
{
"operatingsystem": "Debian",
"operatingsystemrelease": [
"6",
"7"
]
},
{
"operatingsystem": "Ubuntu",
"operatingsystemrelease": [
"10.04",
"12.04",
"14.04"
]
},
{
"operatingsystem": "Solaris",
"operatingsystemrelease": [
"10",
"11"
]
},
{
"operatingsystem": "Windows",
"operatingsystemrelease": [
"Server 2003",
"Server 2003 R2",
"Server 2008",
"Server 2008 R2",
"Server 2012",
"Server 2012 R2",
"7",
"8"
]
},
{
"operatingsystem": "AIX",
"operatingsystemrelease": [
"5.3",
"6.1",
"7.1"
]
}
],
"requirements": [
{
"name": "pe",
"version_requirement": "3.x"
},
{
"name": "puppet",
"version_requirement": ">=2.7.20 <4.0.0"
}
],
"description": "Standard Library for Puppet Modules",
"dependencies": [
]
}

View File

@ -7,7 +7,7 @@ describe 'abs function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operati
pp = <<-EOS
$input = '-34.56'
$output = abs($input)
notify { $output: }
notify { "$output": }
EOS
apply_manifest(pp, :catch_failures => true) do |r|
@ -19,7 +19,7 @@ describe 'abs function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operati
pp = <<-EOS
$input = -34.56
$output = abs($input)
notify { $output: }
notify { "$output": }
EOS
apply_manifest(pp, :catch_failures => true) do |r|

View File

@ -25,7 +25,7 @@ describe 'any2array function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('o
EOS
apply_manifest(pp, :catch_failures => true) do |r|
expect(r.stdout).to match(/Notice: Output: testarray/)
expect(r.stdout).to match(/Notice: Output: (\[|)test(,\s|)array(\]|)/)
end
end
@ -42,7 +42,7 @@ describe 'any2array function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('o
EOS
apply_manifest(pp, :catch_failures => true) do |r|
expect(r.stdout).to match(/Notice: Output: testarray/)
expect(r.stdout).to match(/Notice: Output: (\[|)test(,\s|)array(\]|)/)
end
end
end

View File

@ -4,11 +4,11 @@ require 'spec_helper_acceptance'
describe 'bool2num function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
describe 'success' do
['false', 'f', '0', 'n', 'no'].each do |bool|
it 'should convert a given boolean, #{bool}, to 0' do
it "should convert a given boolean, #{bool}, to 0" do
pp = <<-EOS
$input = #{bool}
$input = "#{bool}"
$output = bool2num($input)
notify { $output: }
notify { "$output": }
EOS
apply_manifest(pp, :catch_failures => true) do |r|
@ -18,11 +18,11 @@ describe 'bool2num function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('op
end
['true', 't', '1', 'y', 'yes'].each do |bool|
it 'should convert a given boolean, #{bool}, to 1' do
it "should convert a given boolean, #{bool}, to 1" do
pp = <<-EOS
$input = #{bool}
$input = "#{bool}"
$output = bool2num($input)
notify { $output: }
notify { "$output": }
EOS
apply_manifest(pp, :catch_failures => true) do |r|

View File

@ -0,0 +1,39 @@
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'
describe 'ceiling function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
describe 'success' do
it 'ceilings floats' do
pp = <<-EOS
$a = 12.8
$b = 13
$o = ceiling($a)
if $o == $b {
notify { 'output correct': }
}
EOS
apply_manifest(pp, :catch_failures => true) do |r|
expect(r.stdout).to match(/Notice: output correct/)
end
end
it 'ceilings integers' do
pp = <<-EOS
$a = 7
$b = 7
$o = ceiling($a)
if $o == $b {
notify { 'output correct': }
}
EOS
apply_manifest(pp, :catch_failures => true) do |r|
expect(r.stdout).to match(/Notice: output correct/)
end
end
end
describe 'failure' do
it 'handles improper argument counts'
it 'handles non-numbers'
end
end

View File

@ -19,7 +19,7 @@ describe 'chop function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operat
end
it 'should eat the last two characters of \r\n' do
pp = <<-EOS
pp = <<-'EOS'
$input = "test\r\n"
if size($input) != 6 {
fail("Size of ${input} is not 6.")

View File

@ -12,6 +12,28 @@ describe 'concat function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('oper
}
EOS
apply_manifest(pp, :catch_failures => true)
end
it 'should concat arrays and primitives to array' do
pp = <<-EOS
$output = concat(['1','2','3'],'4','5','6',['7','8','9'])
validate_array($output)
if size($output) != 9 {
fail("${output} should have 9 elements.")
}
EOS
apply_manifest(pp, :catch_failures => true)
end
it 'should concat multiple arrays to one' do
pp = <<-EOS
$output = concat(['1','2','3'],['4','5','6'],['7','8','9'])
validate_array($output)
if size($output) != 9 {
fail("${output} should have 9 elements.")
}
EOS
apply_manifest(pp, :catch_failures => true)
end
end

View File

@ -7,7 +7,7 @@ describe 'count function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('opera
pp = <<-EOS
$input = [1,2,3,4]
$output = count($input)
notify { $output: }
notify { "$output": }
EOS
apply_manifest(pp, :catch_failures => true) do |r|
@ -19,7 +19,7 @@ describe 'count function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('opera
pp = <<-EOS
$input = [1,1,1,2]
$output = count($input, 1)
notify { $output: }
notify { "$output": }
EOS
apply_manifest(pp, :catch_failures => true) do |r|

View File

@ -1,18 +1,16 @@
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'
describe 'ensure_packages function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
describe 'ensure_packages function', :unless => fact('osfamily') =~ /windows/i do
describe 'success' do
it 'ensure_packages a package' do
apply_manifest('package { "zsh": ensure => absent, }')
apply_manifest('package { "rake": ensure => absent, provider => "gem", }')
pp = <<-EOS
$a = "zsh"
ensure_packages($a)
$a = "rake"
ensure_packages($a,{'provider' => 'gem'})
EOS
apply_manifest(pp, :expect_changes => true) do |r|
expect(r.stdout).to match(/Package\[zsh\]\/ensure: created/)
end
apply_manifest(pp, :expect_changes => true)
end
it 'ensures a package already declared'
it 'takes defaults arguments'

View File

@ -1,18 +1,16 @@
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'
describe 'ensure_resource function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
describe 'ensure_resource function', :unless => fact('osfamily') =~ /windows/i do
describe 'success' do
it 'ensure_resource a package' do
apply_manifest('package { "zsh": ensure => absent, }')
apply_manifest('package { "rake": ensure => absent, provider => "gem", }')
pp = <<-EOS
$a = "zsh"
ensure_resource('package', $a)
$a = "rake"
ensure_resource('package', $a, {'provider' => 'gem'})
EOS
apply_manifest(pp, :expect_changes => true) do |r|
expect(r.stdout).to match(/Package\[zsh\]\/ensure: created/)
end
apply_manifest(pp, :expect_changes => true)
end
it 'ensures a resource already declared'
it 'takes defaults arguments'

View File

@ -0,0 +1,60 @@
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'
describe 'fqdn_rand_string function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
describe 'success' do
let(:facts_d) do
if fact('is_pe', '--puppet') == "true"
if fact('osfamily') =~ /windows/i
if fact('kernelmajversion').to_f < 6.0
'c:/documents and settings/all users/application data/puppetlabs/facter/facts.d'
else
'c:/programdata/puppetlabs/facter/facts.d'
end
else
'/etc/puppetlabs/facter/facts.d'
end
else
'/etc/facter/facts.d'
end
end
after :each do
shell("if [ -f '#{facts_d}/fqdn.txt' ] ; then rm '#{facts_d}/fqdn.txt' ; fi")
end
before :each do
#no need to create on windows, pe creates by default
if fact('osfamily') !~ /windows/i
shell("mkdir -p '#{facts_d}'")
end
end
it 'generates random alphanumeric strings' do
shell("echo fqdn=fakehost.localdomain > '#{facts_d}/fqdn.txt'")
pp = <<-eos
$l = 10
$o = fqdn_rand_string($l)
notice(inline_template('fqdn_rand_string is <%= @o.inspect %>'))
eos
apply_manifest(pp, :catch_failures => true) do |r|
expect(r.stdout).to match(/fqdn_rand_string is "7oDp0KOr1b"/)
end
end
it 'generates random alphanumeric strings with custom seeds' do
shell("echo fqdn=fakehost.localdomain > '#{facts_d}/fqdn.txt'")
pp = <<-eos
$l = 10
$s = 'seed'
$o = fqdn_rand_string($l, undef, $s)
notice(inline_template('fqdn_rand_string is <%= @o.inspect %>'))
eos
apply_manifest(pp, :catch_failures => true) do |r|
expect(r.stdout).to match(/fqdn_rand_string is "3HS4mbuI3E"/)
end
end
end
describe 'failure' do
it 'handles improper argument counts'
it 'handles non-numbers for length argument'
end
end

View File

@ -4,17 +4,31 @@ require 'spec_helper_acceptance'
describe 'fqdn_rotate function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
describe 'success' do
let(:facts_d) do
if fact('is_pe') == "true"
'/etc/puppetlabs/facter/facts.d'
if fact('is_pe', '--puppet') == "true"
if fact('osfamily') =~ /windows/i
if fact('kernelmajversion').to_f < 6.0
'C:/Documents and Settings/All Users/Application Data/PuppetLabs/facter/facts.d'
else
'C:/ProgramData/PuppetLabs/facter/facts.d'
end
else
'/etc/puppetlabs/facter/facts.d'
end
else
'/etc/facter/facts.d'
end
end
after :each do
shell("if [ -f #{facts_d}/fqdn.txt ] ; then rm #{facts_d}/fqdn.txt ; fi")
shell("if [ -f '#{facts_d}/fqdn.txt' ] ; then rm '#{facts_d}/fqdn.txt' ; fi")
end
before :each do
#No need to create on windows, PE creates by default
if fact('osfamily') !~ /windows/i
shell("mkdir -p '#{facts_d}'")
end
end
it 'fqdn_rotates floats' do
shell("echo 'fqdn=fakehost.localdomain' > #{facts_d}/fqdn.txt")
shell("echo fqdn=fakehost.localdomain > '#{facts_d}/fqdn.txt'")
pp = <<-EOS
$a = ['a','b','c','d']
$o = fqdn_rotate($a)

View File

@ -3,22 +3,6 @@ require 'spec_helper_acceptance'
describe 'get_module_path function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
describe 'success' do
it 'get_module_paths stdlib' do
pp = <<-EOS
$a = $::is_pe ? {
'true' => '/opt/puppet/share/puppet/modules/stdlib',
'false' => '/etc/puppet/modules/stdlib',
}
$o = get_module_path('stdlib')
if $o == $a {
notify { 'output correct': }
}
EOS
apply_manifest(pp, :catch_failures => true) do |r|
expect(r.stdout).to match(/Notice: output correct/)
end
end
it 'get_module_paths dne' do
pp = <<-EOS
$a = $::is_pe ? {
@ -28,6 +12,8 @@ describe 'get_module_path function', :unless => UNSUPPORTED_PLATFORMS.include?(f
$o = get_module_path('dne')
if $o == $a {
notify { 'output correct': }
} else {
notify { "failed; module path is '$o'": }
}
EOS

View File

@ -3,18 +3,17 @@ require 'spec_helper_acceptance'
describe 'getparam function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
describe 'success' do
it 'getparam a package' do
it 'getparam a notify' do
pp = <<-EOS
user { "rspec":
ensure => present,
managehome => true,
notify { 'rspec':
message => 'custom rspec message',
}
$o = getparam(User['rspec'], 'managehome')
$o = getparam(Notify['rspec'], 'message')
notice(inline_template('getparam is <%= @o.inspect %>'))
EOS
apply_manifest(pp, :catch_failures => true) do |r|
expect(r.stdout).to match(/getparam is true/)
expect(r.stdout).to match(/getparam is "custom rspec message"/)
end
end
end

View File

@ -1,11 +1,11 @@
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'
describe 'has_interface_with function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
describe 'has_interface_with function', :unless => ((UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem'))) or (fact('osfamily') == 'windows') or (fact('osfamily') == 'AIX')) do
describe 'success' do
it 'has_interface_with existing ipaddress' do
pp = <<-EOS
$a = '127.0.0.1'
$a = $::ipaddress
$o = has_interface_with('ipaddress', $a)
notice(inline_template('has_interface_with is <%= @o.inspect %>'))
EOS
@ -27,7 +27,17 @@ describe 'has_interface_with function', :unless => UNSUPPORTED_PLATFORMS.include
end
it 'has_interface_with existing interface' do
pp = <<-EOS
$a = 'lo'
if $osfamily == 'Solaris' or $osfamily == 'Darwin' {
$a = 'lo0'
}elsif $osfamily == 'windows' {
$a = $::kernelmajversion ? {
/6\.(2|3|4)/ => 'Ethernet0',
/6\.(0|1)/ => 'Local_Area_Connection',
/5\.(1|2)/ => undef, #Broken current in facter
}
}else {
$a = 'lo'
}
$o = has_interface_with($a)
notice(inline_template('has_interface_with is <%= @o.inspect %>'))
EOS

View File

@ -1,7 +1,7 @@
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'
describe 'has_ip_address function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
describe 'has_ip_address function', :unless => ((UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem'))) or (fact('osfamily') == 'windows') or (fact('osfamily') == 'AIX')) do
describe 'success' do
it 'has_ip_address existing ipaddress' do
pp = <<-EOS

View File

@ -1,7 +1,7 @@
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'
describe 'has_ip_network function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
describe 'has_ip_network function', :unless => ((UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem'))) or (fact('osfamily') == 'windows') or (fact('osfamily') == 'AIX')) do
describe 'success' do
it 'has_ip_network existing ipaddress' do
pp = <<-EOS

View File

@ -1,16 +1,18 @@
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'
tmpdir = default.tmpdir('stdlib')
describe 'loadyaml function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
describe 'success' do
it 'loadyamls array of values' do
shell('echo "---
shell("echo '---
aaa: 1
bbb: 2
ccc: 3
ddd: 4" > /testyaml.yaml')
ddd: 4' > #{tmpdir}/testyaml.yaml")
pp = <<-EOS
$o = loadyaml('/testyaml.yaml')
$o = loadyaml('#{tmpdir}/testyaml.yaml')
notice(inline_template('loadyaml[aaa] is <%= @o["aaa"].inspect %>'))
notice(inline_template('loadyaml[bbb] is <%= @o["bbb"].inspect %>'))
notice(inline_template('loadyaml[ccc] is <%= @o["ccc"].inspect %>'))

View File

@ -2,6 +2,13 @@
require 'spec_helper_acceptance'
describe 'member function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
shared_examples 'item found' do
it 'should output correctly' do
apply_manifest(pp, :catch_failures => true) do |r|
expect(r.stdout).to match(/Notice: output correct/)
end
end
end
describe 'success' do
it 'members arrays' do
pp = <<-EOS
@ -18,8 +25,29 @@ describe 'member function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('oper
expect(r.stdout).to match(/Notice: output correct/)
end
end
describe 'members array of integers' do
it_should_behave_like 'item found' do
let(:pp) { <<-EOS
if member( [1,2,3,4], 4 ){
notify { 'output correct': }
}
EOS
}
end
end
describe 'members of mixed array' do
it_should_behave_like 'item found' do
let(:pp) { <<-EOS
if member( ['a','4',3], 'a' ){
notify { 'output correct': }
}
EOS
}
end
end
it 'members arrays without members'
end
describe 'failure' do
it 'handles improper argument counts'
end

View File

@ -14,9 +14,9 @@ describe 'merge function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('opera
EOS
apply_manifest(pp, :catch_failures => true) do |r|
expect(r.stdout).to match(/merge\[one\] is "1"/)
expect(r.stdout).to match(/merge\[one\] is ("1"|1)/)
expect(r.stdout).to match(/merge\[two\] is "dos"/)
expect(r.stdout).to match(/merge\[three\] is {"five"=>"5"}/)
expect(r.stdout).to match(/merge\[three\] is {"five"=>("5"|5)}/)
end
end
end

View File

@ -0,0 +1,10 @@
HOSTS:
centos-59-x64:
roles:
- master
platform: el-5-x86_64
box : centos-59-x64-vbox4210-nocm
box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-59-x64-vbox4210-nocm.box
hypervisor : vagrant
CONFIG:
type: git

View File

@ -0,0 +1,10 @@
HOSTS:
centos-65-x64:
roles:
- master
platform: el-6-x86_64
box : centos-65-x64-vbox436-nocm
box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-65-x64-virtualbox-nocm.box
hypervisor : vagrant
CONFIG:
type: foss

View File

@ -0,0 +1,11 @@
HOSTS:
ubuntu-server-1404-x64:
roles:
- master
platform: ubuntu-14.04-amd64
box : puppetlabs/ubuntu-14.04-64-nocm
box_url : https://vagrantcloud.com/puppetlabs/ubuntu-14.04-64-nocm
hypervisor : vagrant
CONFIG:
log_level : debug
type: git

View File

@ -0,0 +1,26 @@
HOSTS:
ubuntu1204:
roles:
- master
- database
- dashboard
platform: ubuntu-12.04-amd64
template: ubuntu-1204-x86_64
hypervisor: vcloud
win2003_i386:
roles:
- agent
- default
platform: windows-2003-i386
template: win-2003-i386
hypervisor: vcloud
CONFIG:
nfs_server: none
ssh:
keys: "~/.ssh/id_rsa-acceptance"
consoleport: 443
datastore: instance0
folder: Delivery/Quality Assurance/Enterprise/Dynamic
resourcepool: delivery/Quality Assurance/Enterprise/Dynamic
pooling_api: http://vcloud.delivery.puppetlabs.net/
pe_dir: http://neptune.puppetlabs.lan/3.2/ci-ready/

View File

@ -0,0 +1,26 @@
HOSTS:
ubuntu1204:
roles:
- master
- database
- dashboard
platform: ubuntu-12.04-amd64
template: ubuntu-1204-x86_64
hypervisor: vcloud
win2003_x86_64:
roles:
- agent
- default
platform: windows-2003-x86_64
template: win-2003-x86_64
hypervisor: vcloud
CONFIG:
nfs_server: none
ssh:
keys: "~/.ssh/id_rsa-acceptance"
consoleport: 443
datastore: instance0
folder: Delivery/Quality Assurance/Enterprise/Dynamic
resourcepool: delivery/Quality Assurance/Enterprise/Dynamic
pooling_api: http://vcloud.delivery.puppetlabs.net/
pe_dir: http://neptune.puppetlabs.lan/3.2/ci-ready/

View File

@ -0,0 +1,26 @@
HOSTS:
ubuntu1204:
roles:
- master
- database
- dashboard
platform: ubuntu-12.04-amd64
template: ubuntu-1204-x86_64
hypervisor: vcloud
win2008_x86_64:
roles:
- agent
- default
platform: windows-2008-x86_64
template: win-2008-x86_64
hypervisor: vcloud
CONFIG:
nfs_server: none
ssh:
keys: "~/.ssh/id_rsa-acceptance"
consoleport: 443
datastore: instance0
folder: Delivery/Quality Assurance/Enterprise/Dynamic
resourcepool: delivery/Quality Assurance/Enterprise/Dynamic
pooling_api: http://vcloud.delivery.puppetlabs.net/
pe_dir: http://neptune.puppetlabs.lan/3.2/ci-ready/

View File

@ -0,0 +1,26 @@
HOSTS:
ubuntu1204:
roles:
- master
- database
- dashboard
platform: ubuntu-12.04-amd64
template: ubuntu-1204-x86_64
hypervisor: vcloud
win2008r2:
roles:
- agent
- default
platform: windows-2008r2-x86_64
template: win-2008r2-x86_64
hypervisor: vcloud
CONFIG:
nfs_server: none
ssh:
keys: "~/.ssh/id_rsa-acceptance"
consoleport: 443
datastore: instance0
folder: Delivery/Quality Assurance/Enterprise/Dynamic
resourcepool: delivery/Quality Assurance/Enterprise/Dynamic
pooling_api: http://vcloud.delivery.puppetlabs.net/
pe_dir: http://neptune.puppetlabs.lan/3.2/ci-ready/

View File

@ -0,0 +1,26 @@
HOSTS:
ubuntu1204:
roles:
- master
- database
- dashboard
platform: ubuntu-12.04-amd64
template: ubuntu-1204-x86_64
hypervisor: vcloud
win2012:
roles:
- agent
- default
platform: windows-2012-x86_64
template: win-2012-x86_64
hypervisor: vcloud
CONFIG:
nfs_server: none
ssh:
keys: "~/.ssh/id_rsa-acceptance"
consoleport: 443
datastore: instance0
folder: Delivery/Quality Assurance/Enterprise/Dynamic
resourcepool: delivery/Quality Assurance/Enterprise/Dynamic
pooling_api: http://vcloud.delivery.puppetlabs.net/
pe_dir: http://neptune.puppetlabs.lan/3.2/ci-ready/

View File

@ -0,0 +1,26 @@
HOSTS:
ubuntu1204:
roles:
- master
- database
- dashboard
platform: ubuntu-12.04-amd64
template: ubuntu-1204-x86_64
hypervisor: vcloud
win2012r2:
roles:
- agent
- default
platform: windows-2012r2-x86_64
template: win-2012r2-x86_64
hypervisor: vcloud
CONFIG:
nfs_server: none
ssh:
keys: "~/.ssh/id_rsa-acceptance"
consoleport: 443
datastore: instance0
folder: Delivery/Quality Assurance/Enterprise/Dynamic
resourcepool: delivery/Quality Assurance/Enterprise/Dynamic
pooling_api: http://vcloud.delivery.puppetlabs.net/
pe_dir: http://neptune.puppetlabs.lan/3.2/ci-ready/

View File

@ -26,7 +26,7 @@ describe 'parseyaml function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('o
EOS
apply_manifest(pp, :expect_failures => true) do |r|
expect(r.stderr).to match(/syntax error/)
expect(r.stderr).to match(/(syntax error|did not find expected key)/)
end
end

View File

@ -0,0 +1,34 @@
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'
# Windows and OS X do not have useful implementations of crypt(3)
describe 'pw_hash function', :unless => (UNSUPPORTED_PLATFORMS + ['windows', 'Darwin']).include?(fact('operatingsystem')) do
describe 'success' do
it 'hashes passwords' do
pp = <<-EOS
$o = pw_hash('password', 'sha-512', 'salt')
notice(inline_template('pw_hash is <%= @o.inspect %>'))
EOS
apply_manifest(pp, :catch_failures => true) do |r|
expect(r.stdout).to match(/pw_hash is "\$6\$salt\$IxDD3jeSOb5eB1CX5LBsqZFVkJdido3OUILO5Ifz5iwMuTS4XMS130MTSuDDl3aCI6WouIL9AjRbLCelDCy\.g\."/)
end
end
it 'returns nil if no password is provided' do
pp = <<-EOS
$o = pw_hash('', 'sha-512', 'salt')
notice(inline_template('pw_hash is <%= @o.inspect %>'))
EOS
apply_manifest(pp, :catch_failures => true) do |r|
expect(r.stdout).to match(/pw_hash is nil/)
end
end
end
describe 'failure' do
it 'handles less than three arguments'
it 'handles more than three arguments'
it 'handles non strings'
end
end

View File

@ -5,14 +5,14 @@ describe 'shuffle function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('ope
describe 'success' do
it 'shuffles arrays' do
pp = <<-EOS
$a = ["the","public","art","galleries"]
$a = ["1", "2", "3", "4", "5", "6", "7", "8", "the","public","art","galleries"]
# Anagram: Large picture halls, I bet
$o = shuffle($a)
notice(inline_template('shuffle is <%= @o.inspect %>'))
EOS
apply_manifest(pp, :catch_failures => true) do |r|
expect(r.stdout).to_not match(/shuffle is \["the", "public", "art", "galleries"\]/)
expect(r.stdout).to_not match(/shuffle is \["1", "2", "3", "4", "5", "6", "7", "8", "the", "public", "art", "galleries"\]/)
end
end
it 'shuffles strings' do

View File

@ -1,7 +1,7 @@
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'
describe 'type function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
describe 'type function', :unless => (UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) || is_future_parser_enabled?) do
describe 'success' do
it 'types arrays' do
pp = <<-EOS

View File

@ -1,7 +1,7 @@
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'
describe 'validate_augeas function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
describe 'validate_augeas function', :unless => ((UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem'))) or (fact('osfamily') == 'windows')) do
describe 'prep' do
it 'installs augeas for tests'
end

View File

@ -37,10 +37,12 @@ describe 'validate_cmd function', :unless => UNSUPPORTED_PLATFORMS.include?(fact
} else {
$two = '/bin/aoeu'
}
validate_cmd($one,$two,"aoeu is dvorak)
validate_cmd($one,$two,"aoeu is dvorak")
EOS
expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/aoeu is dvorak/)
apply_manifest(pp, :expect_failures => true) do |output|
expect(output.stderr).to match(/aoeu is dvorak/)
end
end
end
describe 'failure' do

View File

@ -13,8 +13,12 @@ describe 'values function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('oper
$output = values($arg)
notice(inline_template('<%= @output.sort.inspect %>'))
EOS
if is_future_parser_enabled?
expect(apply_manifest(pp, :catch_failures => true).stdout).to match(/\[1, 2, 3\]/)
else
expect(apply_manifest(pp, :catch_failures => true).stdout).to match(/\["1", "2", "3"\]/)
end
expect(apply_manifest(pp, :catch_failures => true).stdout).to match(/\["1", "2", "3"\]/)
end
end
describe 'failure' do

View File

@ -11,8 +11,11 @@ describe 'zip function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operati
$output = zip($one,$two)
notice(inline_template('<%= @output.inspect %>'))
EOS
expect(apply_manifest(pp, :catch_failures => true).stdout).to match(/\[\["1", "5"\], \["2", "6"\], \["3", "7"\], \["4", "8"\]\]/)
if is_future_parser_enabled?
expect(apply_manifest(pp, :catch_failures => true).stdout).to match(/\[\[1, 5\], \[2, 6\], \[3, 7\], \[4, 8\]\]/)
else
expect(apply_manifest(pp, :catch_failures => true).stdout).to match(/\[\["1", "5"\], \["2", "6"\], \["3", "7"\], \["4", "8"\]\]/)
end
end
it 'zips two arrays of numbers & bools together' do
pp = <<-EOS
@ -21,8 +24,11 @@ describe 'zip function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operati
$output = zip($one,$two)
notice(inline_template('<%= @output.inspect %>'))
EOS
expect(apply_manifest(pp, :catch_failures => true).stdout).to match(/\[\["1", true\], \["2", true\], \["three", false\], \["4", false\]\]/)
if is_future_parser_enabled?
expect(apply_manifest(pp, :catch_failures => true).stdout).to match(/\[\[1, true\], \[2, true\], \["three", false\], \[4, false\]\]/)
else
expect(apply_manifest(pp, :catch_failures => true).stdout).to match(/\[\["1", true\], \["2", true\], \["three", false\], \["4", false\]\]/)
end
end
it 'zips two arrays of numbers together and flattens them' do
# XXX This only tests the argument `true`, even though the following are valid:
@ -35,8 +41,11 @@ describe 'zip function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operati
$output = zip($one,$two,true)
notice(inline_template('<%= @output.inspect %>'))
EOS
expect(apply_manifest(pp, :catch_failures => true).stdout).to match(/\["1", "5", "2", "6", "3", "7", "4", "8"\]/)
if is_future_parser_enabled?
expect(apply_manifest(pp, :catch_failures => true).stdout).to match(/\[1, 5, 2, 6, 3, 7, 4, 8\]/)
else
expect(apply_manifest(pp, :catch_failures => true).stdout).to match(/\["1", "5", "2", "6", "3", "7", "4", "8"\]/)
end
end
it 'handles unmatched length' do
# XXX Is this expected behavior?
@ -46,8 +55,11 @@ describe 'zip function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operati
$output = zip($one,$two)
notice(inline_template('<%= @output.inspect %>'))
EOS
expect(apply_manifest(pp, :catch_failures => true).stdout).to match(/\[\["1", "5"\], \["2", "6"\]\]/)
if is_future_parser_enabled?
expect(apply_manifest(pp, :catch_failures => true).stdout).to match(/\[\[1, 5\], \[2, 6\]\]/)
else
expect(apply_manifest(pp, :catch_failures => true).stdout).to match(/\[\["1", "5"\], \["2", "6"\]\]/)
end
end
end
describe 'failure' do

View File

@ -6,20 +6,20 @@ describe "the abs function" do
let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("abs").should == "function_abs"
expect(Puppet::Parser::Functions.function("abs")).to eq("function_abs")
end
it "should raise a ParseError if there is less than 1 arguments" do
lambda { scope.function_abs([]) }.should( raise_error(Puppet::ParseError))
expect { scope.function_abs([]) }.to( raise_error(Puppet::ParseError))
end
it "should convert a negative number into a positive" do
result = scope.function_abs(["-34"])
result.should(eq(34))
expect(result).to(eq(34))
end
it "should do nothing with a positive number" do
result = scope.function_abs(["5678"])
result.should(eq(5678))
expect(result).to(eq(5678))
end
end

View File

@ -5,51 +5,51 @@ describe "the any2array function" do
let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("any2array").should == "function_any2array"
expect(Puppet::Parser::Functions.function("any2array")).to eq("function_any2array")
end
it "should return an empty array if there is less than 1 argument" do
result = scope.function_any2array([])
result.should(eq([]))
expect(result).to(eq([]))
end
it "should convert boolean true to [ true ] " do
result = scope.function_any2array([true])
result.should(eq([true]))
expect(result).to(eq([true]))
end
it "should convert one object to [object]" do
result = scope.function_any2array(['one'])
result.should(eq(['one']))
expect(result).to(eq(['one']))
end
it "should convert multiple objects to [objects]" do
result = scope.function_any2array(['one', 'two'])
result.should(eq(['one', 'two']))
expect(result).to(eq(['one', 'two']))
end
it "should return empty array it was called with" do
result = scope.function_any2array([[]])
result.should(eq([]))
expect(result).to(eq([]))
end
it "should return one-member array it was called with" do
result = scope.function_any2array([['string']])
result.should(eq(['string']))
expect(result).to(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']))
expect(result).to(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']))
expect(result).to(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([]))
expect(result).to(eq([]))
end
end

View File

@ -0,0 +1,55 @@
#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe Puppet::Parser::Functions.function(:assert_private) do
let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
subject do
function_name = Puppet::Parser::Functions.function(:assert_private)
scope.method(function_name)
end
context "when called from inside module" do
it "should not fail" do
scope.expects(:lookupvar).with('module_name').returns('foo')
scope.expects(:lookupvar).with('caller_module_name').returns('foo')
expect {
subject.call []
}.not_to raise_error
end
end
context "with an explicit failure message" do
it "prints the failure message on error" do
scope.expects(:lookupvar).with('module_name').returns('foo')
scope.expects(:lookupvar).with('caller_module_name').returns('bar')
expect {
subject.call ['failure message!']
}.to raise_error Puppet::ParseError, /failure message!/
end
end
context "when called from private class" do
it "should fail with a class error message" do
scope.expects(:lookupvar).with('module_name').returns('foo')
scope.expects(:lookupvar).with('caller_module_name').returns('bar')
scope.source.expects(:name).returns('foo::baz')
scope.source.expects(:type).returns('hostclass')
expect {
subject.call []
}.to raise_error Puppet::ParseError, /Class foo::baz is private/
end
end
context "when called from private definition" do
it "should fail with a class error message" do
scope.expects(:lookupvar).with('module_name').returns('foo')
scope.expects(:lookupvar).with('caller_module_name').returns('bar')
scope.source.expects(:name).returns('foo::baz')
scope.source.expects(:type).returns('definition')
expect {
subject.call []
}.to raise_error Puppet::ParseError, /Definition foo::baz is private/
end
end
end

View File

@ -6,7 +6,7 @@ describe "the base64 function" do
let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("base64").should == "function_base64"
expect(Puppet::Parser::Functions.function("base64")).to eq("function_base64")
end
it "should raise a ParseError if there are other than 2 arguments" do
@ -25,10 +25,10 @@ describe "the base64 function" do
it "should encode a encoded string" do
result = scope.function_base64(["encode",'thestring'])
result.should =~ /\AdGhlc3RyaW5n\n\Z/
expect(result).to match(/\AdGhlc3RyaW5n\n\Z/)
end
it "should decode a base64 encoded string" do
result = scope.function_base64(["decode",'dGhlc3RyaW5n'])
result.should == 'thestring'
expect(result).to eq('thestring')
end
end

View File

@ -5,20 +5,34 @@ describe "the bool2num function" do
let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("bool2num").should == "function_bool2num"
expect(Puppet::Parser::Functions.function("bool2num")).to eq("function_bool2num")
end
it "should raise a ParseError if there is less than 1 arguments" do
lambda { scope.function_bool2num([]) }.should( raise_error(Puppet::ParseError))
expect { scope.function_bool2num([]) }.to( raise_error(Puppet::ParseError))
end
it "should convert true to 1" do
result = scope.function_bool2num([true])
expect(result).to(eq(1))
end
it "should convert 'true' to 1" do
result = scope.function_bool2num(['true'])
result.should(eq(1))
end
it "should convert false to 0" do
result = scope.function_bool2num([false])
result.should(eq(0))
it "should convert 'false' to 0" do
result = scope.function_bool2num(['false'])
expect(result).to(eq(0))
end
it "should accept objects which extend String" do
class AlsoString < String
end
value = AlsoString.new('true')
result = scope.function_bool2num([value])
result.should(eq(1))
end
end

View File

@ -5,15 +5,24 @@ describe "the capitalize function" do
let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("capitalize").should == "function_capitalize"
expect(Puppet::Parser::Functions.function("capitalize")).to eq("function_capitalize")
end
it "should raise a ParseError if there is less than 1 arguments" do
lambda { scope.function_capitalize([]) }.should( raise_error(Puppet::ParseError))
expect { scope.function_capitalize([]) }.to( raise_error(Puppet::ParseError))
end
it "should capitalize the beginning of a string" do
result = scope.function_capitalize(["abc"])
result.should(eq("Abc"))
expect(result).to(eq("Abc"))
end
it "should accept objects which extend String" do
class AlsoString < String
end
value = AlsoString.new('abc')
result = scope.function_capitalize([value])
result.should(eq('Abc'))
end
end

View File

@ -0,0 +1,39 @@
#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the ceiling function" do
let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
expect(Puppet::Parser::Functions.function("ceiling")).to eq("function_ceiling")
end
it "should raise a ParseError if there is less than 1 argument" do
expect { scope.function_ceiling([]) }.to( raise_error(Puppet::ParseError, /Wrong number of arguments/))
end
it "should should raise a ParseError if input isn't numeric (eg. String)" do
expect { scope.function_ceiling(["foo"]) }.to( raise_error(Puppet::ParseError, /Wrong argument type/))
end
it "should should raise a ParseError if input isn't numeric (eg. Boolean)" do
expect { scope.function_ceiling([true]) }.to( raise_error(Puppet::ParseError, /Wrong argument type/))
end
it "should return an integer when a numeric type is passed" do
result = scope.function_ceiling([12.4])
expect(result.is_a?(Integer)).to(eq(true))
end
it "should return the input when an integer is passed" do
result = scope.function_ceiling([7])
expect(result).to(eq(7))
end
it "should return the smallest integer greater than or equal to the input" do
result = scope.function_ceiling([3.8])
expect(result).to(eq(4))
end
end

View File

@ -5,15 +5,24 @@ describe "the chomp function" do
let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("chomp").should == "function_chomp"
expect(Puppet::Parser::Functions.function("chomp")).to eq("function_chomp")
end
it "should raise a ParseError if there is less than 1 arguments" do
lambda { scope.function_chomp([]) }.should( raise_error(Puppet::ParseError))
expect { scope.function_chomp([]) }.to( raise_error(Puppet::ParseError))
end
it "should chomp the end of a string" do
result = scope.function_chomp(["abc\n"])
expect(result).to(eq("abc"))
end
it "should accept objects which extend String" do
class AlsoString < String
end
value = AlsoString.new("abc\n")
result = scope.function_chomp([value])
result.should(eq("abc"))
end
end

View File

@ -5,15 +5,24 @@ describe "the chop function" do
let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("chop").should == "function_chop"
expect(Puppet::Parser::Functions.function("chop")).to eq("function_chop")
end
it "should raise a ParseError if there is less than 1 arguments" do
lambda { scope.function_chop([]) }.should( raise_error(Puppet::ParseError))
expect { scope.function_chop([]) }.to( raise_error(Puppet::ParseError))
end
it "should chop the end of a string" do
result = scope.function_chop(["asdf\n"])
result.should(eq("asdf"))
expect(result).to(eq("asdf"))
end
it "should accept objects which extend String" do
class AlsoString < String
end
value = AlsoString.new("abc\n")
result = scope.function_chop([value])
result.should(eq('abc'))
end
end

Some files were not shown because too many files have changed in this diff Show More