Initial commit

This commit is contained in:
Eugene Kirpichov 2012-09-07 17:38:58 -07:00
commit a7a56f1f71
151 changed files with 5671 additions and 0 deletions

View File

@ -0,0 +1,5 @@
source :rubygems
puppetversion = ENV.key?('PUPPET_VERSION') ? "= #{ENV['PUPPET_VERSION']}" : ['>= 2.7']
gem 'puppet', puppetversion
gem 'puppetlabs_spec_helper', '>= 0.1.0'

4
deployment/puppet/stdlib/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
pkg/
.DS_Store
metadata.json
coverage/

View File

@ -0,0 +1,16 @@
language: ruby
rvm:
- 1.8.7
before_script:
after_script:
script: "rake spec_full"
branches:
only:
- master
env:
- PUPPET_VERSION=2.7.13
- PUPPET_VERSION=2.7.6
- PUPPET_VERSION=2.6.9
notifications:
email: false
gemfile: .gemfile

View File

@ -0,0 +1,86 @@
2012-05-22 - Peter Meier <peter.meier@immerda.ch> - 2.3.3
* fix regression in #11017 properly (f0a62c7)
2012-05-10 - Jeff McCune <jeff@puppetlabs.com> - 2.3.3
* Fix spec tests using the new spec_helper (7d34333)
2012-05-10 - Puppet Labs <support@puppetlabs.com> - 2.3.2
* Make file_line default to ensure => present (1373e70)
* Memoize file_line spec instance variables (20aacc5)
* Fix spec tests using the new spec_helper (1ebfa5d)
* (#13595) initialize_everything_for_tests couples modules Puppet ver (3222f35)
* (#13439) Fix MRI 1.9 issue with spec_helper (15c5fd1)
* (#13439) Fix test failures with Puppet 2.6.x (665610b)
* (#13439) refactor spec helper for compatibility with both puppet 2.7 and master (82194ca)
* (#13494) Specify the behavior of zero padded strings (61891bb)
2012-03-29 Puppet Labs <support@puppetlabs.com> - 2.1.3
* (#11607) Add Rakefile to enable spec testing
* (#12377) Avoid infinite loop when retrying require json
2012-03-13 Puppet Labs <support@puppetlabs.com> - 2.3.1
* (#13091) Fix LoadError bug with puppet apply and puppet_vardir fact
2012-03-12 Puppet Labs <support@puppetlabs.com> - 2.3.0
* Add a large number of new Puppet functions
* Backwards compatibility preserved with 2.2.x
2011-12-30 Puppet Labs <support@puppetlabs.com> - 2.2.1
* Documentation only release for the Forge
2011-12-30 Puppet Labs <support@puppetlabs.com> - 2.1.2
* Documentation only release for PE 2.0.x
2011-11-08 Puppet Labs <support@puppetlabs.com> - 2.2.0
* #10285 - Refactor json to use pson instead.
* Maint - Add watchr autotest script
* Maint - Make rspec tests work with Puppet 2.6.4
* #9859 - Add root_home fact and tests
2011-08-18 Puppet Labs <support@puppetlabs.com> - 2.1.1
* Change facts.d paths to match Facter 2.0 paths.
* /etc/facter/facts.d
* /etc/puppetlabs/facter/facts.d
2011-08-17 Puppet Labs <support@puppetlabs.com> - 2.1.0
* Add R.I. Pienaar's facts.d custom facter fact
* facts defined in /etc/facts.d and /etc/puppetlabs/facts.d are
automatically loaded now.
2011-08-04 Puppet Labs <support@puppetlabs.com> - 2.0.0
* Rename whole_line to file_line
* This is an API change and as such motivating a 2.0.0 release according to semver.org.
2011-08-04 Puppet Labs <support@puppetlabs.com> - 1.1.0
* Rename append_line to whole_line
* This is an API change and as such motivating a 1.1.0 release.
2011-08-04 Puppet Labs <support@puppetlabs.com> - 1.0.0
* Initial stable release
* Add validate_array and validate_string functions
* Make merge() function work with Ruby 1.8.5
* Add hash merging function
* Add has_key function
* Add loadyaml() function
* Add append_line native
2011-06-21 Jeff McCune <jeff@puppetlabs.com> - 0.1.7
* Add validate_hash() and getvar() functions
2011-06-15 Jeff McCune <jeff@puppetlabs.com> - 0.1.6
* Add anchor resource type to provide containment for composite classes
2011-06-03 Jeff McCune <jeff@puppetlabs.com> - 0.1.5
* Add validate_bool() function to stdlib
0.1.4 2011-05-26 Jeff McCune <jeff@puppetlabs.com>
* Move most stages after main
0.1.3 2011-05-25 Jeff McCune <jeff@puppetlabs.com>
* Add validate_re() function
0.1.2 2011-05-24 Jeff McCune <jeff@puppetlabs.com>
* Update to add annotated tag
0.1.1 2011-05-24 Jeff McCune <jeff@puppetlabs.com>
* Add stdlib::stages class with a standard set of stages

View File

@ -0,0 +1,19 @@
Copyright (C) 2011 Puppet Labs Inc
and some parts:
Copyright (C) 2011 Krzysztof Wilczynski
Puppet Labs can be contacted at: info@puppetlabs.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1,11 @@
name 'puppetlabs-stdlib'
version '2.3.3'
source 'git://github.com/puppetlabs/puppetlabs-stdlib'
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'

View File

@ -0,0 +1,89 @@
# Puppet Labs Standard Library #
This module provides a "standard library" of resources for developing Puppet
Modules. This modules will include the following additions to Puppet
* Stages
* Facts
* Functions
* Defined resource types
* Types
* Providers
This module is officially curated and provided by Puppet Labs. The modules
Puppet Labs writes and distributes will make heavy use of this standard
library.
# Versions #
This module follows semver.org (v1.0.0) versioning guidelines. The standard
library module is released as part of [Puppet
Enterprise](http://puppetlabs.com/puppet/puppet-enterprise/) and as a result
older versions of Puppet Enterprise that Puppet Labs still supports will have
bugfix maintenance branches periodically "merged up" into master. The current
list of integration branches are:
* v2.1.x (v2.1.1 released in PE 1.2, 1.2.1, 1.2.3, 1.2.4)
* v2.2.x (Never released as part of PE, only to the Forge)
* v2.3.x (Scheduled for next PE feature release)
* master (mainline development branch)
The first Puppet Enterprise version including the stdlib module is Puppet
Enterprise 1.2.
# Compatibility #
## stdlib v2.1.x, v2.2.x ##
v2.1.x and v2.2.x of this module are designed to work with Puppet versions
2.6.x and 2.7.x. There are currently no plans for a Puppet 0.25 standard
library module.
## stdlib v2.3.x ##
While not yet released, the standard library may only work with Puppet 2.7.x.
# Functions #
Please see `puppet doc -r function` for documentation on each function. The
current list of functions is:
* getvar
* has\_key
* loadyaml
* merge.rb
* validate\_array
* validate\_bool
* validate\_hash
* validate\_re
* validate\_string
## validate\_hash ##
$somehash = { 'one' => 'two' }
validate\_hash($somehash)
## getvar() ##
This function aims to look up variables in user-defined namespaces within
puppet. Note, if the namespace is a class, it should already be evaluated
before the function is used.
$namespace = 'site::data'
include "${namespace}"
$myvar = getvar("${namespace}::myvar")
## Facts ##
Facts in `/etc/facter/facts.d` and `/etc/puppetlabs/facter/facts.d` are now loaded
automatically. This is a direct copy of R.I. Pienaar's custom facter fact
located at:
[https://github.com/ripienaar/facter-facts/tree/master/facts-dot-d](https://github.com/ripienaar/facter-facts/tree/master/facts-dot-d)
stdlib releases beyond 2.x will not include external fact support using
facts-dot-d. Instead, these versions of stdlib require Facter 2.0 which
includes external fact support in the main Facter codebase.
Please see [2157](http://projects.puppetlabs.com/issues/2157) for more
information.

View File

@ -0,0 +1,35 @@
Puppet Specific Facts
=====================
Facter is meant to stand alone and apart from Puppet. However, Facter often
runs inside Puppet and all custom facts included in the stdlib module will
almost always be evaluated in the context of Puppet and Facter working
together.
Still, we don't want to write custom facts that blow up in the users face if
Puppet is not loaded in memory. This is often the case if the user run
`facter` without also supplying the `--puppet` flag.
Ah! But Jeff, the custom fact won't be in the `$LOAD_PATH` unless the user
supplies `--facter`! You might say...
Not (always) true I say! If the user happens to have a CWD of
`<modulepath>/stdlib/lib` then the facts will automatically be evaluated and
blow up.
In any event, it's pretty easy to write a fact that has no value if Puppet is
not loaded. Simply do it like this:
Facter.add(:node_vardir) do
setcode do
# This will be nil if Puppet is not available.
Facter::Util::PuppetSettings.with_puppet do
Puppet[:vardir]
end
end
end
The `Facter::Util::PuppetSettings.with_puppet` method accepts a block and
yields to it only if the Puppet library is loaded. If the Puppet library is
not loaded, then the method silently returns `nil` which Facter interprets as
an undefined fact value. The net effect is that the fact won't be set.

View File

@ -0,0 +1,25 @@
# Contributing to this module #
* Work in a topic branch
* Submit a github pull request
* Address any comments / feeback
* Merge into master using --no-ff
# Releasing this module #
* This module adheres to http://semver.org/
* Look for API breaking changes using git diff vX.Y.Z..master
* If no API breaking changes, the minor version may be bumped.
* If there are API breaking changes, the major version must be bumped.
* If there are only small minor changes, the patch version may be bumped.
* Update the CHANGELOG
* Update the Modulefile
* Commit these changes with a message along the lines of "Update CHANGELOG and
Modulefile for release"
* Create an annotated tag with git tag -a vX.Y.Z -m 'version X.Y.Z' (NOTE the
leading v as per semver.org)
* Push the tag with git push origin --tags
* Build a new package with puppet-module or the rake build task if it exists
* Publish the new package to the forge
* Bonus points for an announcement to puppet-users.

View File

@ -0,0 +1,2 @@
require 'rubygems'
require 'puppetlabs_spec_helper/rake_tasks'

View File

@ -0,0 +1,26 @@
# This facter fact returns the value of the Puppet vardir setting for the node
# running puppet or puppet agent. The intent is to enable Puppet modules to
# automatically have insight into a place where they can place variable data,
# regardless of the node's platform.
#
# The value should be directly usable in a File resource path attribute.
begin
require 'facter/util/puppet_settings'
rescue LoadError => e
# puppet apply does not add module lib directories to the $LOAD_PATH (See
# #4248). It should (in the future) but for the time being we need to be
# defensive which is what this rescue block is doing.
rb_file = File.join(File.dirname(__FILE__), 'util', 'puppet_settings.rb')
load rb_file if File.exists?(rb_file) or raise e
end
Facter.add(:puppet_vardir) do
setcode do
# This will be nil if Puppet is not available.
Facter::Util::PuppetSettings.with_puppet do
Puppet[:vardir]
end
end
end

View File

@ -0,0 +1,19 @@
# A facter fact to determine the root home directory.
# This varies on PE supported platforms and may be
# reconfigured by the end user.
module Facter::Util::RootHome
class << self
def get_root_home
root_ent = Facter::Util::Resolution.exec("getent passwd root")
# The home directory is the sixth element in the passwd entry
# If the platform doesn't have getent, root_ent will be nil and we should
# return it straight away.
root_ent && root_ent.split(":")[5]
end
end
end
Facter.add(:root_home) do
setcode { Facter::Util::RootHome.get_root_home }
end

View File

@ -0,0 +1,21 @@
module Facter
module Util
module PuppetSettings
# This method is intended to provide a convenient way to evaluate a
# Facter code block only if Puppet is loaded. This is to account for the
# situation where the fact happens to be in the load path, but Puppet is
# not loaded for whatever reason. Perhaps the user is simply running
# facter without the --puppet flag and they happen to be working in a lib
# directory of a module.
def self.with_puppet
begin
Module.const_get("Puppet")
rescue NameError
nil
else
yield
end
end
end
end
end

View File

@ -0,0 +1,36 @@
#
# abs.rb
#
module Puppet::Parser::Functions
newfunction(:abs, :type => :rvalue, :doc => <<-EOS
Returns the absolute value of a number, for example -34.56 becomes
34.56. Takes a single integer and float value as an argument.
EOS
) do |arguments|
raise(Puppet::ParseError, "abs(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
# Numbers in Puppet are often string-encoded which is troublesome ...
if value.is_a?(String)
if value.match(/^-?(?:\d+)(?:\.\d+){1}$/)
value = value.to_f
elsif value.match(/^-?\d+$/)
value = value.to_i
else
raise(Puppet::ParseError, 'abs(): Requires float or ' +
'integer to work with')
end
end
# We have numeric value to handle ...
result = value.abs
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,49 @@
#
# bool2num.rb
#
module Puppet::Parser::Functions
newfunction(:bool2num, :type => :rvalue, :doc => <<-EOS
Converts a boolean to a number. Converts the values:
false, f, 0, n, and no to 0
true, t, 1, y, and yes to 1
Requires a single boolean or string as an input.
EOS
) do |arguments|
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
# We have real boolean values as well ...
result = value ? 1 : 0
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,34 @@
#
# capitalize.rb
#
module Puppet::Parser::Functions
newfunction(:capitalize, :type => :rvalue, :doc => <<-EOS
Capitalizes the first letter of a string or array of strings.
Requires either a single string or an array as an input.
EOS
) do |arguments|
raise(Puppet::ParseError, "capitalize(): 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, 'capitalize(): 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.capitalize : i }
else
result = value.capitalize
end
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,35 @@
#
# chomp.rb
#
module Puppet::Parser::Functions
newfunction(:chomp, :type => :rvalue, :doc => <<-'EOS'
Removes the record separator from the end of a string or an array of
strings, for example `hello\n` becomes `hello`.
Requires a single string or array as an input.
EOS
) do |arguments|
raise(Puppet::ParseError, "chomp(): 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, 'chomp(): 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.chomp : i }
else
result = value.chomp
end
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,37 @@
#
# chop.rb
#
module Puppet::Parser::Functions
newfunction(:chop, :type => :rvalue, :doc => <<-'EOS'
Returns a new string with the last character removed. If the string ends
with `\r\n`, both characters are removed. Applying chop to an empty
string returns an empty string. If you wish to merely remove record
separators then you should use the `chomp` function.
Requires a string or array of strings as input.
EOS
) do |arguments|
raise(Puppet::ParseError, "chop(): 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, 'chop(): Requires either an ' +
'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.chop : i }
else
result = value.chop
end
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,34 @@
#
# delete.rb
#
# TODO(Krzysztof Wilczynski): We need to add support for regular expression ...
# TODO(Krzysztof Wilczynski): Support for strings and hashes too ...
module Puppet::Parser::Functions
newfunction(:delete, :type => :rvalue, :doc => <<-EOS
Deletes a selected element from an array.
*Examples:*
delete(['a','b','c'], 'b')
Would return: ['a','c']
EOS
) do |arguments|
if (arguments.size != 2) then
raise(Puppet::ParseError, "delete(): Wrong number of arguments "+
"given #{arguments.size} for 2")
end
a = arguments[0]
item = arguments[1]
a.delete(item)
a
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,49 @@
#
# delete_at.rb
#
module Puppet::Parser::Functions
newfunction(:delete_at, :type => :rvalue, :doc => <<-EOS
Deletes a determined indexed value from an array.
*Examples:*
delete_at(['a','b','c'], 1)
Would return: ['a','c']
EOS
) do |arguments|
raise(Puppet::ParseError, "delete_at(): Wrong number of arguments " +
"given (#{arguments.size} for 2)") if arguments.size < 2
array = arguments[0]
unless array.is_a?(Array)
raise(Puppet::ParseError, 'delete_at(): Requires array to work with')
end
index = arguments[1]
if index.is_a?(String) and not index.match(/^\d+$/)
raise(Puppet::ParseError, 'delete_at(): You must provide ' +
'non-negative numeric index')
end
result = array.clone
# Numbers in Puppet are often string-encoded which is troublesome ...
index = index.to_i
if index > result.size - 1 # First element is at index 0 is it not?
raise(Puppet::ParseError, 'delete_at(): Given index ' +
'exceeds size of array given')
end
result.delete_at(index) # We ignore the element that got deleted ...
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,33 @@
#
# downcase.rb
#
module Puppet::Parser::Functions
newfunction(:downcase, :type => :rvalue, :doc => <<-EOS
Converts the case of a string or all strings in an array to lower case.
EOS
) do |arguments|
raise(Puppet::ParseError, "downcase(): 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, 'downcase(): 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.downcase : i }
else
result = value.downcase
end
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,28 @@
#
# empty.rb
#
module Puppet::Parser::Functions
newfunction(:empty, :type => :rvalue, :doc => <<-EOS
Returns true if the variable is empty.
EOS
) do |arguments|
raise(Puppet::ParseError, "empty(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
klass = value.class
unless [Array, Hash, String].include?(klass)
raise(Puppet::ParseError, 'empty(): Requires either ' +
'array, hash or string to work with')
end
result = value.empty?
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,33 @@
#
# flatten.rb
#
module Puppet::Parser::Functions
newfunction(:flatten, :type => :rvalue, :doc => <<-EOS
This function flattens any deeply nested arrays and returns a single flat array
as a result.
*Examples:*
flatten(['a', ['b', ['c']]])
Would return: ['a','b','c']
EOS
) do |arguments|
raise(Puppet::ParseError, "flatten(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
array = arguments[0]
unless array.is_a?(Array)
raise(Puppet::ParseError, 'flatten(): Requires array to work with')
end
result = array.flatten
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,46 @@
#
# fqdn_rotate.rb
#
module Puppet::Parser::Functions
newfunction(:fqdn_rotate, :type => :rvalue, :doc => <<-EOS
Rotates an array a random number of times based on a nodes fqdn.
EOS
) do |arguments|
raise(Puppet::ParseError, "fqdn_rotate(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
klass = value.class
require 'digest/md5'
unless [Array, String].include?(klass)
raise(Puppet::ParseError, 'fqdn_rotate(): Requires either ' +
'array or string to work with')
end
result = value.clone
string = value.is_a?(String) ? true : false
# Check whether it makes sense to rotate ...
return result if result.size <= 1
# We turn any string value into an array to be able to rotate ...
result = string ? result.split('') : result
elements = result.size
srand(Digest::MD5.hexdigest([lookupvar('::fqdn'),arguments].join(':')).hex)
rand(elements).times {
result.push result.shift
}
result = string ? result.join : result
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,17 @@
module Puppet::Parser::Functions
newfunction(:get_module_path, :type =>:rvalue, :doc => <<-EOT
Returns the absolute path of the specified module for the current
environment.
Example:
$module_path = get_module_path('stdlib')
EOT
) do |args|
raise(Puppet::ParseError, "get_module_name(): Wrong number of arguments, expects one") unless args.size == 1
if module_path = Puppet::Module.find(args[0], compiler.environment.to_s)
module_path.path
else
raise(Puppet::ParseError, "Could not find module #{args[0]} in environment #{compiler.environment}")
end
end
end

View File

@ -0,0 +1,26 @@
module Puppet::Parser::Functions
newfunction(:getvar, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args|
Lookup a variable in a remote namespace.
For example:
$foo = getvar('site::data::foo')
# Equivalent to $foo = $site::data::foo
This is useful if the namespace itself is stored in a string:
$datalocation = 'site::data'
$bar = getvar("${datalocation}::bar")
# Equivalent to $bar = $site::data::bar
ENDHEREDOC
unless args.length == 1
raise Puppet::ParseError, ("getvar(): wrong number of arguments (#{args.length}; must be 1)")
end
self.lookupvar("#{args[0]}")
end
end

View File

@ -0,0 +1,33 @@
#
# grep.rb
#
module Puppet::Parser::Functions
newfunction(:grep, :type => :rvalue, :doc => <<-EOS
This function searches through an array and returns any elements that match
the provided regular expression.
*Examples:*
grep(['aaa','bbb','ccc','aaaddd'], 'aaa')
Would return:
['aaa','aaaddd']
EOS
) do |arguments|
if (arguments.size != 2) then
raise(Puppet::ParseError, "grep(): Wrong number of arguments "+
"given #{arguments.size} for 2")
end
a = arguments[0]
pattern = Regexp.new(arguments[1])
a.grep(pattern)
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,28 @@
module Puppet::Parser::Functions
newfunction(:has_key, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args|
Determine if a hash has a certain key value.
Example:
$my_hash = {'key_one' => 'value_one'}
if has_key($my_hash, 'key_two') {
notice('we will not reach here')
}
if has_key($my_hash, 'key_one') {
notice('this will be printed')
}
ENDHEREDOC
unless args.length == 2
raise Puppet::ParseError, ("has_key(): wrong number of arguments (#{args.length}; must be 2)")
end
unless args[0].is_a?(Hash)
raise Puppet::ParseError, "has_key(): expects the first argument to be a hash, got #{args[0].inspect} which is of type #{args[0].class}"
end
args[0].has_key?(args[1])
end
end

View File

@ -0,0 +1,41 @@
#
# hash.rb
#
module Puppet::Parser::Functions
newfunction(:hash, :type => :rvalue, :doc => <<-EOS
This function converts and array into a hash.
*Examples:*
hash(['a',1,'b',2,'c',3])
Would return: {'a'=>1,'b'=>2,'c'=>3}
EOS
) do |arguments|
raise(Puppet::ParseError, "hash(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
array = arguments[0]
unless array.is_a?(Array)
raise(Puppet::ParseError, 'hash(): Requires array to work with')
end
result = {}
begin
# This is to make it compatible with older version of Ruby ...
array = array.flatten
result = Hash[*array]
rescue Exception
raise(Puppet::ParseError, 'hash(): Unable to compute ' +
'hash from array given')
end
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,22 @@
#
# is_array.rb
#
module Puppet::Parser::Functions
newfunction(:is_array, :type => :rvalue, :doc => <<-EOS
Returns true if the variable passed to this function is an array.
EOS
) do |arguments|
raise(Puppet::ParseError, "is_array(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
type = arguments[0]
result = type.is_a?(Array)
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,47 @@
#
# is_domain_name.rb
#
module Puppet::Parser::Functions
newfunction(:is_domain_name, :type => :rvalue, :doc => <<-EOS
Returns true if the string passed to this function is a syntactically correct domain name.
EOS
) do |arguments|
if (arguments.size != 1) then
raise(Puppet::ParseError, "is_domain_name(): Wrong number of arguments "+
"given #{arguments.size} for 1")
end
domain = arguments[0]
# Limits (rfc1035, 3.1)
domain_max_length=255
label_min_length=1
label_max_length=63
# Allow ".", it is the top level domain
return true if domain == '.'
# Remove the final dot, if present.
domain.chomp!('.')
# Check the whole domain
return false if domain.empty?
return false if domain.length > domain_max_length
# Check each label in the domain
labels = domain.split('.')
vlabels = labels.each do |label|
break if label.length < label_min_length
break if label.length > label_max_length
break if label[-1..-1] == '-'
break if label[0..0] == '-'
break unless /^[a-z\d-]+$/i.match(label)
end
return vlabels == labels
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,27 @@
#
# is_float.rb
#
module Puppet::Parser::Functions
newfunction(:is_float, :type => :rvalue, :doc => <<-EOS
Returns true if the variable passed to this function is a float.
EOS
) do |arguments|
if (arguments.size != 1) then
raise(Puppet::ParseError, "is_float(): Wrong number of arguments "+
"given #{arguments.size} for 1")
end
value = arguments[0]
if value != value.to_f.to_s then
return false
else
return true
end
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,22 @@
#
# is_hash.rb
#
module Puppet::Parser::Functions
newfunction(:is_hash, :type => :rvalue, :doc => <<-EOS
Returns true if the variable passed to this function is a hash.
EOS
) do |arguments|
raise(Puppet::ParseError, "is_hash(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size != 1
type = arguments[0]
result = type.is_a?(Hash)
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,27 @@
#
# is_integer.rb
#
module Puppet::Parser::Functions
newfunction(:is_integer, :type => :rvalue, :doc => <<-EOS
Returns true if the variable returned to this string is an integer.
EOS
) do |arguments|
if (arguments.size != 1) then
raise(Puppet::ParseError, "is_integer(): Wrong number of arguments "+
"given #{arguments.size} for 1")
end
value = arguments[0]
if value != value.to_i.to_s then
return false
else
return true
end
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,32 @@
#
# is_ip_address.rb
#
module Puppet::Parser::Functions
newfunction(:is_ip_address, :type => :rvalue, :doc => <<-EOS
Returns true if the string passed to this function is a valid IP address.
EOS
) do |arguments|
require 'ipaddr'
if (arguments.size != 1) then
raise(Puppet::ParseError, "is_ip_address(): Wrong number of arguments "+
"given #{arguments.size} for 1")
end
begin
ip = IPAddr.new(arguments[0])
rescue ArgumentError
return false
end
if ip.ipv4? or ip.ipv6? then
return true
else
return false
end
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,27 @@
#
# is_mac_address.rb
#
module Puppet::Parser::Functions
newfunction(:is_mac_address, :type => :rvalue, :doc => <<-EOS
Returns true if the string passed to this function is a valid mac address.
EOS
) do |arguments|
if (arguments.size != 1) then
raise(Puppet::ParseError, "is_mac_address(): Wrong number of arguments "+
"given #{arguments.size} for 1")
end
mac = arguments[0]
if /^[a-fA-F0-9]{1,2}:[a-fA-F0-9]{1,2}:[a-fA-F0-9]{1,2}:[a-fA-F0-9]{1,2}:[a-fA-F0-9]{1,2}:[a-fA-F0-9]{1,2}$/.match(mac) then
return true
else
return false
end
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,27 @@
#
# is_numeric.rb
#
module Puppet::Parser::Functions
newfunction(:is_numeric, :type => :rvalue, :doc => <<-EOS
Returns true if the variable passed to this function is a number.
EOS
) do |arguments|
if (arguments.size != 1) then
raise(Puppet::ParseError, "is_numeric(): Wrong number of arguments "+
"given #{arguments.size} for 1")
end
value = arguments[0]
if value == value.to_f.to_s or value == value.to_i.to_s then
return true
else
return false
end
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,26 @@
#
# is_string.rb
#
module Puppet::Parser::Functions
newfunction(:is_string, :type => :rvalue, :doc => <<-EOS
Returns true if the variable passed to this function is a string.
EOS
) do |arguments|
raise(Puppet::ParseError, "is_string(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
type = arguments[0]
result = type.is_a?(String)
if result and (type == type.to_f.to_s or type == type.to_i.to_s) then
return false
end
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,41 @@
#
# join.rb
#
module Puppet::Parser::Functions
newfunction(:join, :type => :rvalue, :doc => <<-EOS
This function joins an array into a string using a seperator.
*Examples:*
join(['a','b','c'], ",")
Would result in: "a,b,c"
EOS
) do |arguments|
# Technically we support two arguments but only first is mandatory ...
raise(Puppet::ParseError, "join(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
array = arguments[0]
unless array.is_a?(Array)
raise(Puppet::ParseError, 'join(): Requires array to work with')
end
suffix = arguments[1] if arguments[1]
if suffix
unless suffix.is_a?(String)
raise(Puppet::ParseError, 'join(): Requires string to work with')
end
end
result = suffix ? array.join(suffix) : array.join
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,26 @@
#
# keys.rb
#
module Puppet::Parser::Functions
newfunction(:keys, :type => :rvalue, :doc => <<-EOS
Returns the keys of a hash as an array.
EOS
) do |arguments|
raise(Puppet::ParseError, "keys(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
hash = arguments[0]
unless hash.is_a?(Hash)
raise(Puppet::ParseError, 'keys(): Requires hash to work with')
end
result = hash.keys
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,20 @@
module Puppet::Parser::Functions
newfunction(:loadyaml, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args|
Load a YAML file containing an array, string, or hash, and return the data
in the corresponding native data type.
For example:
$myhash = loadyaml('/etc/puppet/data/myhash.yaml')
ENDHEREDOC
unless args.length == 1
raise Puppet::ParseError, ("loadyaml(): wrong number of arguments (#{args.length}; must be 1)")
end
YAML.load_file(args[0])
end
end

View File

@ -0,0 +1,33 @@
#
# lstrip.rb
#
module Puppet::Parser::Functions
newfunction(:lstrip, :type => :rvalue, :doc => <<-EOS
Strips leading spaces to the left of a string.
EOS
) do |arguments|
raise(Puppet::ParseError, "lstrip(): 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, 'lstrip(): 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.lstrip : i }
else
result = value.lstrip
end
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,44 @@
#
# member.rb
#
# TODO(Krzysztof Wilczynski): We need to add support for regular expression ...
# TODO(Krzysztof Wilczynski): Support for strings and hashes too ...
module Puppet::Parser::Functions
newfunction(:member, :type => :rvalue, :doc => <<-EOS
This function determines if a variable is a member of an array.
*Examples:*
member(['a','b'], 'b')
Would return: true
member(['a','b'], 'c')
Would return: false
EOS
) do |arguments|
raise(Puppet::ParseError, "member(): Wrong number of arguments " +
"given (#{arguments.size} for 2)") if arguments.size < 2
array = arguments[0]
unless array.is_a?(Array)
raise(Puppet::ParseError, 'member(): Requires array to work with')
end
item = arguments[1]
raise(Puppet::ParseError, 'member(): You must provide item ' +
'to search for within array given') if item.empty?
result = array.include?(item)
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,33 @@
module Puppet::Parser::Functions
newfunction(:merge, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args|
Merges two or more hashes together and returns the resulting hash.
For example:
$hash1 = {'one' => 1, 'two', => 2}
$hash2 = {'two' => 'dos', 'three', => 'tres'}
$merged_hash = merge($hash1, $hash2)
# The resulting hash is equivalent to:
# $merged_hash = {'one' => 1, 'two' => 'dos', 'three' => 'tres'}
When there is a duplicate key, the key in the rightmost hash will "win."
ENDHEREDOC
if args.length < 2
raise Puppet::ParseError, ("merge(): wrong number of arguments (#{args.length}; must be at least 2)")
end
# The hash we accumulate into
accumulator = Hash.new
# Merge into the accumulator hash
args.each do |arg|
unless arg.is_a?(Hash)
raise Puppet::ParseError, "merge: unexpected argument type #{arg.class}, only expects hash arguments"
end
accumulator.merge!(arg)
end
# Return the fully merged hash
accumulator
end
end

View File

@ -0,0 +1,40 @@
#
# num2bool.rb
#
# TODO(Krzysztof Wilczynski): We probably need to approach numeric values differently ...
module Puppet::Parser::Functions
newfunction(:num2bool, :type => :rvalue, :doc => <<-EOS
This function converts a number into a true boolean. Zero becomes false. Numbers
higher then 0 become true.
EOS
) do |arguments|
raise(Puppet::ParseError, "num2bool(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
number = arguments[0]
# Only numbers allowed ...
unless number.match(/^\-?\d+$/)
raise(Puppet::ParseError, 'num2bool(): Requires integer to work with')
end
result = case number
when /^0$/
false
when /^\-?\d+$/
# Numbers in Puppet are often string-encoded which is troublesome ...
number = number.to_i
# We yield true for any positive number and false otherwise ...
number > 0 ? true : false
else
raise(Puppet::ParseError, 'num2bool(): Unknown numeric format given')
end
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,24 @@
#
# parsejson.rb
#
module Puppet::Parser::Functions
newfunction(:parsejson, :type => :rvalue, :doc => <<-EOS
This function accepts JSON as a string and converts into the correct Puppet
structure.
EOS
) do |arguments|
if (arguments.size != 1) then
raise(Puppet::ParseError, "parsejson(): Wrong number of arguments "+
"given #{arguments.size} for 1")
end
json = arguments[0]
# PSON is natively available in puppet
PSON.load(json)
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,24 @@
#
# parseyaml.rb
#
module Puppet::Parser::Functions
newfunction(:parseyaml, :type => :rvalue, :doc => <<-EOS
This function accepts YAML as a string and converts it into the correct
Puppet structure.
EOS
) do |arguments|
if (arguments.size != 1) then
raise(Puppet::ParseError, "parseyaml(): Wrong number of arguments "+
"given #{arguments.size} for 1")
end
require 'yaml'
YAML::load(arguments[0])
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,45 @@
#
# prefix.rb
#
module Puppet::Parser::Functions
newfunction(:prefix, :type => :rvalue, :doc => <<-EOS
This function applies a prefix to all elements in an array.
*Examles:*
prefix(['a','b','c'], 'p')
Will return: ['pa','pb','pc']
EOS
) do |arguments|
# Technically we support two arguments but only first is mandatory ...
raise(Puppet::ParseError, "prefix(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
array = arguments[0]
unless array.is_a?(Array)
raise(Puppet::ParseError, 'prefix(): Requires array to work with')
end
prefix = arguments[1] if arguments[1]
if prefix
unless prefix.is_a?(String)
raise(Puppet::ParseError, 'prefix(): Requires string to work with')
end
end
# Turn everything into string same as join would do ...
result = array.collect do |i|
i = i.to_s
prefix ? prefix + i : i
end
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,80 @@
#
# range.rb
#
# TODO(Krzysztof Wilczynski): We probably need to approach numeric values differently ...
module Puppet::Parser::Functions
newfunction(:range, :type => :rvalue, :doc => <<-EOS
When given range in the form of (start, stop) it will extrapolate a range as
an array.
*Examples:*
range("0", "9")
Will return: [0,1,2,3,4,5,6,7,8,9]
range("00", "09")
Will return: [0,1,2,3,4,5,6,7,8,9] (Zero padded strings are converted to
integers automatically)
range("a", "c")
Will return: ["a","b","c"]
range("host01", "host10")
Will return: ["host01", "host02", ..., "host09", "host10"]
EOS
) do |arguments|
# We support more than one argument but at least one is mandatory ...
raise(Puppet::ParseError, "range(): Wrong number of " +
"arguments given (#{arguments.size} for 1)") if arguments.size < 1
if arguments.size > 1
start = arguments[0]
stop = arguments[1]
type = '..' # We select simplest type for Range available in Ruby ...
elsif arguments.size > 0
value = arguments[0]
if m = value.match(/^(\w+)(\.\.\.?|\-)(\w+)$/)
start = m[1]
stop = m[3]
type = m[2]
elsif value.match(/^.+$/)
raise(Puppet::ParseError, 'range(): Unable to compute range ' +
'from the value given')
else
raise(Puppet::ParseError, 'range(): Unknown format of range given')
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
range = case type
when /^(\.\.|\-)$/ then (start .. stop)
when /^(\.\.\.)$/ then (start ... stop) # Exclusive of last element ...
end
result = range.collect { |i| i } # Get them all ... Pokemon ...
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,28 @@
#
# reverse.rb
#
module Puppet::Parser::Functions
newfunction(:reverse, :type => :rvalue, :doc => <<-EOS
Reverses the order of a string or array.
EOS
) do |arguments|
raise(Puppet::ParseError, "reverse(): 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, 'reverse(): Requires either ' +
'array or string to work with')
end
result = value.reverse
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,32 @@
#
# rstrip.rb
#
module Puppet::Parser::Functions
newfunction(:rstrip, :type => :rvalue, :doc => <<-EOS
Strips leading spaces to the right of the string.
EOS
) do |arguments|
raise(Puppet::ParseError, "rstrip(): 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, 'rstrip(): Requires either ' +
'array or string to work with')
end
if value.is_a?(Array)
result = value.collect { |i| i.is_a?(String) ? i.rstrip : i }
else
result = value.rstrip
end
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,46 @@
#
# shuffle.rb
#
module Puppet::Parser::Functions
newfunction(:shuffle, :type => :rvalue, :doc => <<-EOS
Randomizes the order of a string or array elements.
EOS
) do |arguments|
raise(Puppet::ParseError, "shuffle(): 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, 'shuffle(): Requires either ' +
'array or string to work with')
end
result = value.clone
string = value.is_a?(String) ? true : false
# Check whether it makes sense to shuffle ...
return result if result.size <= 1
# We turn any string value into an array to be able to shuffle ...
result = string ? result.split('') : result
elements = result.size
# Simple implementation of FisherYates in-place shuffle ...
elements.times do |i|
j = rand(elements - i) + i
result[j], result[i] = result[i], result[j]
end
result = string ? result.join : result
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,48 @@
#
# size.rb
#
# TODO(Krzysztof Wilczynski): Support for hashes would be nice too ...
module Puppet::Parser::Functions
newfunction(:size, :type => :rvalue, :doc => <<-EOS
Returns the number of elements in a string or array.
EOS
) do |arguments|
raise(Puppet::ParseError, "size(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
item = arguments[0]
if item.is_a?(String)
begin
#
# Check whether your item is a numeric value or not ...
# This will take care about positive and/or negative numbers
# for both integer and floating-point values ...
#
# Please note that Puppet has no notion of hexadecimal
# nor octal numbers for its DSL at this point in time ...
#
Float(item)
raise(Puppet::ParseError, 'size(): Requires either ' +
'string or array to work with')
rescue ArgumentError
result = item.size
end
elsif item.is_a?(Array)
result = item.size
else
raise(Puppet::ParseError, 'size(): Unknown type given')
end
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,27 @@
#
# sort.rb
#
module Puppet::Parser::Functions
newfunction(:sort, :type => :rvalue, :doc => <<-EOS
Sorts strings and arrays lexically.
EOS
) do |arguments|
if (arguments.size != 1) then
raise(Puppet::ParseError, "sort(): Wrong number of arguments "+
"given #{arguments.size} for 1")
end
value = arguments[0]
if value.is_a?(Array) then
value.sort
elsif value.is_a?(String) then
value.split("").sort.join("")
end
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,36 @@
#
# squeeze.rb
#
module Puppet::Parser::Functions
newfunction(:squeeze, :type => :rvalue, :doc => <<-EOS
Returns a new string where runs of the same character that occur in this set are replaced by a single character.
EOS
) do |arguments|
if ((arguments.size != 2) and (arguments.size != 1)) then
raise(Puppet::ParseError, "squeeze(): Wrong number of arguments "+
"given #{arguments.size} for 2 or 1")
end
item = arguments[0]
squeezeval = arguments[1]
if item.is_a?(Array) then
if squeezeval then
item.collect { |i| i.squeeze(squeezeval) }
else
item.collect { |i| i.squeeze }
end
else
if squeezeval then
item.squeeze(squeezeval)
else
item.squeeze
end
end
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,41 @@
#
# str2bool.rb
#
module Puppet::Parser::Functions
newfunction(:str2bool, :type => :rvalue, :doc => <<-EOS
This converts a string to a boolean. This attempt to convert strings that
contain things like: y, 1, t, true to 'true' and strings that contain things
like: 0, f, n, false, no to 'false'.
EOS
) do |arguments|
raise(Puppet::ParseError, "str2bool(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
string = arguments[0]
unless string.is_a?(String)
raise(Puppet::ParseError, 'str2bool(): Requires either ' +
'string to work with')
end
# We consider all the yes, no, y, n and so on too ...
result = case string
#
# 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, 'str2bool(): Unknown type of boolean given')
end
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,32 @@
#
# str2saltedsha512.rb
#
module Puppet::Parser::Functions
newfunction(:str2saltedsha512, :type => :rvalue, :doc => <<-EOS
This converts a string to a salted-SHA512 password hash (which is used for
OS X versions >= 10.7). Given any simple string, you will get a hex version
of a salted-SHA512 password hash that can be inserted into your Puppet
manifests as a valid password attribute.
EOS
) do |arguments|
require 'digest/sha2'
raise(Puppet::ParseError, "str2saltedsha512(): Wrong number of arguments " +
"passed (#{arguments.size} but we require 1)") if arguments.size != 1
password = arguments[0]
unless password.is_a?(String)
raise(Puppet::ParseError, 'str2saltedsha512(): Requires a ' +
"String argument, you passed: #{password.class}")
end
seedint = rand(2**31 - 1)
seedstring = Array(seedint).pack("L")
saltedpass = Digest::SHA512.digest(seedstring + password)
(seedstring + saltedpass).unpack('H*')[0]
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,107 @@
#
# strftime.rb
#
module Puppet::Parser::Functions
newfunction(:strftime, :type => :rvalue, :doc => <<-EOS
This function returns formatted time.
*Examples:*
To return the time since epoch:
strftime("%s")
To return the date:
strftime("%Y-%m-%d")
*Format meaning:*
%a - The abbreviated weekday name (``Sun'')
%A - The full weekday name (``Sunday'')
%b - The abbreviated month name (``Jan'')
%B - The full month name (``January'')
%c - The preferred local date and time representation
%C - Century (20 in 2009)
%d - Day of the month (01..31)
%D - Date (%m/%d/%y)
%e - Day of the month, blank-padded ( 1..31)
%F - Equivalent to %Y-%m-%d (the ISO 8601 date format)
%h - Equivalent to %b
%H - Hour of the day, 24-hour clock (00..23)
%I - Hour of the day, 12-hour clock (01..12)
%j - Day of the year (001..366)
%k - hour, 24-hour clock, blank-padded ( 0..23)
%l - hour, 12-hour clock, blank-padded ( 0..12)
%L - Millisecond of the second (000..999)
%m - Month of the year (01..12)
%M - Minute of the hour (00..59)
%n - Newline (\n)
%N - Fractional seconds digits, default is 9 digits (nanosecond)
%3N millisecond (3 digits)
%6N microsecond (6 digits)
%9N nanosecond (9 digits)
%p - Meridian indicator (``AM'' or ``PM'')
%P - Meridian indicator (``am'' or ``pm'')
%r - time, 12-hour (same as %I:%M:%S %p)
%R - time, 24-hour (%H:%M)
%s - Number of seconds since 1970-01-01 00:00:00 UTC.
%S - Second of the minute (00..60)
%t - Tab character (\t)
%T - time, 24-hour (%H:%M:%S)
%u - Day of the week as a decimal, Monday being 1. (1..7)
%U - Week number of the current year,
starting with the first Sunday as the first
day of the first week (00..53)
%v - VMS date (%e-%b-%Y)
%V - Week number of year according to ISO 8601 (01..53)
%W - Week number of the current year,
starting with the first Monday as the first
day of the first week (00..53)
%w - Day of the week (Sunday is 0, 0..6)
%x - Preferred representation for the date alone, no time
%X - Preferred representation for the time alone, no date
%y - Year without a century (00..99)
%Y - Year with century
%z - Time zone as hour offset from UTC (e.g. +0900)
%Z - Time zone name
%% - Literal ``%'' character
EOS
) do |arguments|
# Technically we support two arguments but only first is mandatory ...
raise(Puppet::ParseError, "strftime(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
format = arguments[0]
raise(Puppet::ParseError, 'strftime(): You must provide ' +
'format for evaluation') if format.empty?
# The Time Zone argument is optional ...
time_zone = arguments[1] if arguments[1]
time = Time.new
# There is probably a better way to handle Time Zone ...
if time_zone and not time_zone.empty?
original_zone = ENV['TZ']
local_time = time.clone
local_time = local_time.utc
ENV['TZ'] = time_zone
time = local_time.localtime
ENV['TZ'] = original_zone
end
result = time.strftime(format)
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,39 @@
#
# strip.rb
#
module Puppet::Parser::Functions
newfunction(:strip, :type => :rvalue, :doc => <<-EOS
This function removes leading and trailing whitespace from a string or from
every string inside an array.
*Examples:*
strip(" aaa ")
Would result in: "aaa"
EOS
) do |arguments|
raise(Puppet::ParseError, "strip(): 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, 'strip(): Requires either ' +
'array or string to work with')
end
if value.is_a?(Array)
result = value.collect { |i| i.is_a?(String) ? i.strip : i }
else
result = value.strip
end
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,39 @@
#
# swapcase.rb
#
module Puppet::Parser::Functions
newfunction(:swapcase, :type => :rvalue, :doc => <<-EOS
This function will swap the existing case of a string.
*Examples:*
swapcase("aBcD")
Would result in: "AbCd"
EOS
) do |arguments|
raise(Puppet::ParseError, "swapcase(): 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, 'swapcase(): 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.swapcase : i }
else
result = value.swapcase
end
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,49 @@
#
# time.rb
#
module Puppet::Parser::Functions
newfunction(:time, :type => :rvalue, :doc => <<-EOS
This function will return the current time since epoch as an integer.
*Examples:*
time()
Will return something like: 1311972653
EOS
) do |arguments|
# The Time Zone argument is optional ...
time_zone = arguments[0] if arguments[0]
if (arguments.size != 0) and (arguments.size != 1) then
raise(Puppet::ParseError, "time(): Wrong number of arguments "+
"given #{arguments.size} for 0 or 1")
end
time = Time.new
# There is probably a better way to handle Time Zone ...
if time_zone and not time_zone.empty?
original_zone = ENV['TZ']
local_time = time.clone
local_time = local_time.utc
ENV['TZ'] = time_zone
time = local_time.localtime
ENV['TZ'] = original_zone
end
# Calling Time#to_i on a receiver changes it. Trust me I am the Doctor.
result = time.strftime('%s')
result = result.to_i
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,50 @@
#
# type.rb
#
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
EOS
) do |arguments|
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')
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

@ -0,0 +1,51 @@
#
# unique.rb
#
module Puppet::Parser::Functions
newfunction(:unique, :type => :rvalue, :doc => <<-EOS
This function will remove duplicates from strings and arrays.
*Examples:*
unique("aabbcc")
Will return:
abc
You can also use this with arrays:
unique(["a","a","b","b","c","c"])
This returns:
["a","b","c"]
EOS
) do |arguments|
raise(Puppet::ParseError, "unique(): 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, 'unique(): Requires either ' +
'array or string to work with')
end
result = value.clone
string = value.is_a?(String) ? true : false
# We turn any string value into an array to be able to shuffle ...
result = string ? result.split('') : result
result = result.uniq # Remove duplicates ...
result = string ? result.join : result
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,41 @@
#
# upcase.rb
#
module Puppet::Parser::Functions
newfunction(:upcase, :type => :rvalue, :doc => <<-EOS
Converts a string or an array of strings to uppercase.
*Examples:*
upcase("abcd")
Will return:
ASDF
EOS
) do |arguments|
raise(Puppet::ParseError, "upcase(): 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, 'upcase(): 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.upcase : i }
else
result = value.upcase
end
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,56 @@
module Puppet::Parser::Functions
newfunction(:validate_absolute_path, :doc => <<-'ENDHEREDOC') do |args|
Validate the string represents an absolute path in the filesystem. This function works
for windows and unix style paths.
The following values will pass:
$my_path = "C:/Program Files (x86)/Puppet Labs/Puppet"
validate_absolute_path($my_path)
$my_path2 = "/var/lib/puppet"
validate_absolute_path($my_path2)
The following values will fail, causing compilation to abort:
validate_absolute_path(true)
validate_absolute_path([ 'var/lib/puppet', '/var/foo' ])
validate_absolute_path([ '/var/lib/puppet', 'var/foo' ])
$undefined = undef
validate_absolute_path($undefined)
ENDHEREDOC
require 'puppet/util'
unless args.length > 0 then
raise Puppet::ParseError, ("validate_absolute_path(): wrong number of arguments (#{args.length}; must be > 0)")
end
args.each do |arg|
# This logic was borrowed from
# [lib/puppet/file_serving/base.rb](https://github.com/puppetlabs/puppet/blob/master/lib/puppet/file_serving/base.rb)
# Puppet 2.7 and beyond will have Puppet::Util.absolute_path? Fall back to a back-ported implementation otherwise.
if Puppet::Util.respond_to?(:absolute_path?) then
unless Puppet::Util.absolute_path?(arg, :posix) or Puppet::Util.absolute_path?(arg, :windows)
raise Puppet::ParseError, ("#{arg.inspect} is not an absolute path.")
end
else
# This code back-ported from 2.7.x's lib/puppet/util.rb Puppet::Util.absolute_path?
# Determine in a platform-specific way whether a path is absolute. This
# defaults to the local platform if none is specified.
# Escape once for the string literal, and once for the regex.
slash = '[\\\\/]'
name = '[^\\\\/]+'
regexes = {
:windows => %r!^(([A-Z]:#{slash})|(#{slash}#{slash}#{name}#{slash}#{name})|(#{slash}#{slash}\?#{slash}#{name}))!i,
:posix => %r!^/!,
}
rval = (!!(arg =~ regexes[:posix])) || (!!(arg =~ regexes[:windows]))
rval or raise Puppet::ParseError, ("#{arg.inspect} is not an absolute path.")
end
end
end
end

View File

@ -0,0 +1,33 @@
module Puppet::Parser::Functions
newfunction(:validate_array, :doc => <<-'ENDHEREDOC') do |args|
Validate that all passed values are array data structures. Abort catalog
compilation if any value fails this check.
The following values will pass:
$my_array = [ 'one', 'two' ]
validate_array($my_array)
The following values will fail, causing compilation to abort:
validate_array(true)
validate_array('some_string')
$undefined = undef
validate_array($undefined)
ENDHEREDOC
unless args.length > 0 then
raise Puppet::ParseError, ("validate_array(): wrong number of arguments (#{args.length}; must be > 0)")
end
args.each do |arg|
unless arg.is_a?(Array)
raise Puppet::ParseError, ("#{arg.inspect} is not an Array. It looks to be a #{arg.class}")
end
end
end
end

View File

@ -0,0 +1,34 @@
module Puppet::Parser::Functions
newfunction(:validate_bool, :doc => <<-'ENDHEREDOC') do |args|
Validate that all passed values are either true or false. Abort catalog
compilation if any value fails this check.
The following values will pass:
$iamtrue = true
validate_bool(true)
validate_bool(true, true, false, $iamtrue)
The following values will fail, causing compilation to abort:
$some_array = [ true ]
validate_bool("false")
validate_bool("true")
validate_bool($some_array)
ENDHEREDOC
unless args.length > 0 then
raise Puppet::ParseError, ("validate_bool(): wrong number of arguments (#{args.length}; must be > 0)")
end
args.each do |arg|
unless (arg.is_a?(TrueClass) || arg.is_a?(FalseClass))
raise Puppet::ParseError, ("#{arg.inspect} is not a boolean. It looks to be a #{arg.class}")
end
end
end
end

View File

@ -0,0 +1,33 @@
module Puppet::Parser::Functions
newfunction(:validate_hash, :doc => <<-'ENDHEREDOC') do |args|
Validate that all passed values are hash data structures. Abort catalog
compilation if any value fails this check.
The following values will pass:
$my_hash = { 'one' => 'two' }
validate_hash($my_hash)
The following values will fail, causing compilation to abort:
validate_hash(true)
validate_hash('some_string')
$undefined = undef
validate_hash($undefined)
ENDHEREDOC
unless args.length > 0 then
raise Puppet::ParseError, ("validate_hash(): wrong number of arguments (#{args.length}; must be > 0)")
end
args.each do |arg|
unless arg.is_a?(Hash)
raise Puppet::ParseError, ("#{arg.inspect} is not a Hash. It looks to be a #{arg.class}")
end
end
end
end

View File

@ -0,0 +1,40 @@
module Puppet::Parser::Functions
newfunction(:validate_re, :doc => <<-'ENDHEREDOC') do |args|
Perform simple validation of a string against one or more regular
expressions. The first argument of this function should be a string to
test, and the second argument should be a stringified regular expression
(without the // delimiters) or an array of regular expressions. If none
of the regular expressions match the string passed in, compilation will
abort with a parse error.
If a third argument is specified, this will be the error message raised and
seen by the user.
The following strings will validate against the regular expressions:
validate_re('one', '^one$')
validate_re('one', [ '^one', '^two' ])
The following strings will fail to validate, causing compilation to abort:
validate_re('one', [ '^two', '^three' ])
A helpful error message can be returned like this:
validate_re($::puppetversion, '^2.7', 'The $puppetversion fact value does not match 2.7')
ENDHEREDOC
if (args.length < 2) or (args.length > 3) then
raise Puppet::ParseError, ("validate_re(): wrong number of arguments (#{args.length}; must be 2 or 3)")
end
msg = args[2] || "validate_re(): #{args[0].inspect} does not match #{args[1].inspect}"
# We're using a flattened array here because we can't call String#any? in
# Ruby 1.9 like we can in Ruby 1.8
raise Puppet::ParseError, (msg) unless [args[1]].flatten.any? do |re_str|
args[0] =~ Regexp.compile(re_str)
end
end
end

View File

@ -0,0 +1,52 @@
module Puppet::Parser::Functions
newfunction(:validate_slength, :doc => <<-'ENDHEREDOC') do |args|
Validate that the first argument is a string (or an array of strings), and
less/equal to than the length of the second argument. It fails if the first
argument is not a string or array of strings, and if arg 2 is not convertable
to a number.
The following values will pass:
validate_slength("discombobulate",17)
validate_slength(["discombobulate","moo"],17)
The following valueis will not:
validate_slength("discombobulate",1)
validate_slength(["discombobulate","thermometer"],5)
ENDHEREDOC
raise Puppet::ParseError, ("validate_slength(): Wrong number of arguments (#{args.length}; must be = 2)") unless args.length == 2
unless (args[0].is_a?(String) or args[0].is_a?(Array))
raise Puppet::ParseError, ("validate_slength(): please pass a string, or an array of strings - what you passed didn't work for me at all - #{args[0].class}")
end
begin
max_length = args[1].to_i
rescue NoMethodError => e
raise Puppet::ParseError, ("validate_slength(): Couldn't convert whatever you passed as the length parameter to an integer - sorry: " + e.message )
end
raise Puppet::ParseError, ("validate_slength(): please pass a positive number as max_length") unless max_length > 0
case args[0]
when String
raise Puppet::ParseError, ("validate_slength(): #{args[0].inspect} is #{args[0].length} characters. It should have been less than or equal to #{max_length} characters") unless args[0].length <= max_length
when Array
args[0].each do |arg|
if arg.is_a?(String)
unless ( arg.is_a?(String) and arg.length <= max_length )
raise Puppet::ParseError, ("validate_slength(): #{arg.inspect} is #{arg.length} characters. It should have been less than or equal to #{max_length} characters")
end
else
raise Puppet::ParseError, ("validate_slength(): #{arg.inspect} is not a string, it's a #{arg.class}")
end
end
else
raise Puppet::ParseError, ("validate_slength(): please pass a string, or an array of strings - what you passed didn't work for me at all - #{args[0].class}")
end
end
end

View File

@ -0,0 +1,33 @@
module Puppet::Parser::Functions
newfunction(:validate_string, :doc => <<-'ENDHEREDOC') do |args|
Validate that all passed values are string data structures. Abort catalog
compilation if any value fails this check.
The following values will pass:
$my_string = "one two"
validate_string($my_string, 'three')
The following values will fail, causing compilation to abort:
validate_string(true)
validate_string([ 'some', 'array' ])
$undefined = undef
validate_string($undefined)
ENDHEREDOC
unless args.length > 0 then
raise Puppet::ParseError, ("validate_string(): wrong number of arguments (#{args.length}; must be > 0)")
end
args.each do |arg|
unless arg.is_a?(String)
raise Puppet::ParseError, ("#{arg.inspect} is not a string. It looks to be a #{arg.class}")
end
end
end
end

View File

@ -0,0 +1,39 @@
#
# values.rb
#
module Puppet::Parser::Functions
newfunction(:values, :type => :rvalue, :doc => <<-EOS
When given a hash this function will return the values of that hash.
*Examples:*
$hash = {
'a' => 1,
'b' => 2,
'c' => 3,
}
values($hash)
This example would return:
[1,2,3]
EOS
) do |arguments|
raise(Puppet::ParseError, "values(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
hash = arguments[0]
unless hash.is_a?(Hash)
raise(Puppet::ParseError, 'values(): Requires hash to work with')
end
result = hash.values
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,98 @@
#
# values_at.rb
#
module Puppet::Parser::Functions
newfunction(:values_at, :type => :rvalue, :doc => <<-EOS
Finds value inside an array based on location.
The first argument is the array you want to analyze, and the second element can
be a combination of:
* A single numeric index
* A range in the form of 'start-stop' (eg. 4-9)
* An array combining the above
*Examples*:
values_at(['a','b','c'], 2)
Would return ['c'].
values_at(['a','b','c'], ["0-1"])
Would return ['a','b'].
values_at(['a','b','c','d','e'], [0, "2-3"])
Would return ['a','c','d'].
EOS
) do |arguments|
raise(Puppet::ParseError, "values_at(): Wrong number of " +
"arguments given (#{arguments.size} for 2)") if arguments.size < 2
array = arguments.shift
unless array.is_a?(Array)
raise(Puppet::ParseError, 'values_at(): Requires array to work with')
end
indices = [arguments.shift].flatten() # Get them all ... Pokemon ...
if not indices or indices.empty?
raise(Puppet::ParseError, 'values_at(): You must provide ' +
'at least one positive index to collect')
end
result = []
indices_list = []
indices.each do |i|
if m = i.match(/^(\d+)(\.\.\.?|\-)(\d+)$/)
start = m[1].to_i
stop = m[3].to_i
type = m[2]
if start > stop
raise(Puppet::ParseError, 'values_at(): Stop index in ' +
'given indices range is smaller than the start index')
elsif stop > array.size - 1 # First element is at index 0 is it not?
raise(Puppet::ParseError, 'values_at(): Stop index in ' +
'given indices range exceeds array size')
end
range = case type
when /^(\.\.|\-)$/ then (start .. stop)
when /^(\.\.\.)$/ then (start ... stop) # Exclusive of last element ...
end
range.each { |i| indices_list << i.to_i }
else
# Only positive numbers allowed in this case ...
if not i.match(/^\d+$/)
raise(Puppet::ParseError, 'values_at(): Unknown format ' +
'of given index')
end
# In Puppet numbers are often string-encoded ...
i = i.to_i
if i > array.size - 1 # Same story. First element is at index 0 ...
raise(Puppet::ParseError, 'values_at(): Given index ' +
'exceeds array size')
end
indices_list << i
end
end
# We remove nil values as they make no sense in Puppet DSL ...
result = indices_list.collect { |i| array[i] }.compact
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,65 @@
#
# zip.rb
#
module Puppet::Parser::Functions
newfunction(:zip, :type => :rvalue, :doc => <<-EOS
Takes one element from first array and merges corresponding elements from second array. This generates a sequence of n-element arrays, where n is one more than the count of arguments.
*Example:*
zip(['1','2','3'],['4','5','6'])
Would result in:
["1", "4"], ["2", "5"], ["3", "6"]
EOS
) do |arguments|
# Technically we support three arguments but only first is mandatory ...
raise(Puppet::ParseError, "zip(): Wrong number of arguments " +
"given (#{arguments.size} for 2)") if arguments.size < 2
a = arguments[0]
b = arguments[1]
unless a.is_a?(Array) and b.is_a?(Array)
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
result = a.zip(b)
result = flatten ? result.flatten : result
return result
end
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,59 @@
Puppet::Type.type(:file_line).provide(:ruby) do
def exists?
lines.find do |line|
line.chomp == resource[:line].chomp
end
end
def create
if resource[:match]
handle_create_with_match()
else
handle_create_without_match()
end
end
def destroy
local_lines = lines
File.open(resource[:path],'w') do |fh|
fh.write(local_lines.reject{|l| l.chomp == resource[:line] }.join(''))
end
end
private
def lines
# If this type is ever used with very large files, we should
# write this in a different way, using a temp
# file; for now assuming that this type is only used on
# small-ish config files that can fit into memory without
# too much trouble.
@lines ||= File.readlines(resource[:path])
end
def handle_create_with_match()
regex = resource[:match] ? Regexp.new(resource[:match]) : nil
match_count = lines.select { |l| regex.match(l) }.count
if match_count > 1
raise Puppet::Error, "More than one line in file '#{resource[:path]}' matches pattern '#{resource[:match]}'"
end
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])
end
end
end
def handle_create_without_match
File.open(resource[:path], 'a') do |fh|
fh.puts resource[:line]
end
end
end

View File

@ -0,0 +1,41 @@
Puppet::Type.newtype(:anchor) do
desc <<-'ENDOFDESC'
A simple resource type intended to be used as an anchor in a composite class.
In Puppet 2.6, when a class declares another class, the resources in the
interior class are not contained by the exterior class. This interacts badly
with the pattern of composing complex modules from smaller classes, as it
makes it impossible for end users to specify order relationships between the
exterior class and other modules.
The anchor type lets you work around this. By sandwiching any interior
classes between two no-op resources that _are_ contained by the exterior
class, you can ensure that all resources in the module are contained.
class ntp {
# These classes will have the correct order relationship with each
# other. However, without anchors, they won't have any order
# relationship to Class['ntp'].
class { 'ntp::package': }
-> class { 'ntp::config': }
-> class { 'ntp::service': }
# These two resources "anchor" the composed classes within the ntp
# class.
anchor { 'ntp::begin': } -> Class['ntp::package']
Class['ntp::service'] -> anchor { 'ntp::end': }
}
This allows the end user of the ntp module to establish require and before
relationships with Class['ntp']:
class { 'ntp': } -> class { 'mcollective': }
class { 'mcollective': } -> class { 'ntp': }
ENDOFDESC
newparam :name do
desc "The name of the anchor resource."
end
end

View File

@ -0,0 +1,65 @@
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.
Example:
file_line { 'sudo_rule':
path => '/etc/sudoers',
line => '%sudo ALL=(ALL) ALL',
}
file_line { 'sudo_rule_nopw':
path => '/etc/sudoers',
line => '%sudonopw ALL=(ALL) NOPASSWD: ALL',
}
In this example, Puppet will ensure both of the specified lines are
contained in the file /etc/sudoers.
EOT
ensurable do
defaultvalues
defaultto :present
end
newparam(:name, :namevar => true) do
desc 'An arbitrary name used as the identity of the resource.'
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.'
end
newparam(:line) do
desc 'The line to be appended to the file located by the path parameter.'
end
newparam(:path) do
desc 'The file Puppet will ensure contains the line specified by the line parameter.'
validate do |value|
unless (Puppet.features.posix? and value =~ /^\//) or (Puppet.features.microsoft_windows? and (value =~ /^.:\// or value =~ /^\/\/[^\/]+\/[^\/]+/))
raise(Puppet::Error, "File paths must be fully qualified, not '#{value}'")
end
end
end
validate 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,20 @@
# Class: stdlib
#
# This module manages stdlib. Most of stdlib's features are automatically
# loaded by Puppet, but this class should be declared in order to use the
# standardized run stages.
#
# Parameters: none
#
# Actions:
#
# Declares all other classes in the stdlib module. Currently, this consists
# of stdlib::stages.
#
# Requires: nothing
#
class stdlib {
class { 'stdlib::stages': }
}

View File

@ -0,0 +1,43 @@
# Class: stdlib::stages
#
# This class manages a standard set of run stages for Puppet. It is managed by
# the stdlib class, and should not be declared independently.
#
# The high level stages are (in order):
#
# * setup
# * main
# * runtime
# * setup_infra
# * deploy_infra
# * setup_app
# * deploy_app
# * deploy
#
# Parameters: none
#
# Actions:
#
# Declares various run-stages for deploying infrastructure,
# language runtimes, and application layers.
#
# Requires: nothing
#
# Sample Usage:
#
# node default {
# include stdlib
# class { java: stage => 'runtime' }
# }
#
class stdlib::stages {
stage { 'setup': before => Stage['main'] }
stage { 'runtime': require => Stage['main'] }
-> stage { 'setup_infra': }
-> stage { 'deploy_infra': }
-> stage { 'setup_app': }
-> stage { 'deploy_app': }
-> stage { 'deploy': }
}

View File

@ -0,0 +1,8 @@
require 'rspec'
class Object
# This is necessary because the RAL has a 'should'
# method.
alias :must :should
alias :must_not :should_not
end

View File

@ -0,0 +1,11 @@
# Some monkey-patching to allow us to test private methods.
class Class
def publicize_methods(*methods)
saved_private_instance_methods = methods.empty? ? self.private_instance_methods : methods
self.class_eval { public(*saved_private_instance_methods) }
yield
self.class_eval { private(*saved_private_instance_methods) }
end
end

View File

@ -0,0 +1,6 @@
--format
s
--colour
--loadby
mtime
--backtrace

View File

@ -0,0 +1,12 @@
require 'puppetlabs_spec_helper/puppet_spec_helper'
RSpec.configure do |config|
config.before :each do
GC.disable
end
config.after :each do
GC.enable
end
end

View File

@ -0,0 +1,40 @@
require 'spec_helper'
require 'facter/root_home'
describe Facter::Util::RootHome do
context "solaris" do
let(:root_ent) { "root:x:0:0:Super-User:/:/sbin/sh" }
let(:expected_root_home) { "/" }
it "should return /" do
Facter::Util::Resolution.expects(:exec).with("getent passwd root").returns(root_ent)
Facter::Util::RootHome.get_root_home.should == expected_root_home
end
end
context "linux" do
let(:root_ent) { "root:x:0:0:root:/root:/bin/bash" }
let(:expected_root_home) { "/root" }
it "should return /root" do
Facter::Util::Resolution.expects(:exec).with("getent passwd root").returns(root_ent)
Facter::Util::RootHome.get_root_home.should == expected_root_home
end
end
context "macosx" do
let(:root_ent) { "root:*:0:0:System Administrator:/var/root:/bin/sh" }
let(:expected_root_home) { "/var/root" }
it "should return /var/root" do
Facter::Util::Resolution.expects(:exec).with("getent passwd root").returns(root_ent)
Facter::Util::RootHome.get_root_home.should == expected_root_home
end
end
context "windows" do
before :each do
Facter::Util::Resolution.expects(:exec).with("getent passwd root").returns(nil)
end
it "should be nil on windows" do
Facter::Util::RootHome.get_root_home.should be_nil
end
end
end

View File

@ -0,0 +1,35 @@
require 'spec_helper'
require 'facter/util/puppet_settings'
describe Facter::Util::PuppetSettings do
describe "#with_puppet" do
context "Without Puppet loaded" do
before(:each) do
Module.expects(:const_get).with("Puppet").raises(NameError)
end
it 'should be nil' do
subject.with_puppet { Puppet[:vardir] }.should be_nil
end
it 'should not yield to the block' do
Puppet.expects(:[]).never
subject.with_puppet { Puppet[:vardir] }.should be_nil
end
end
context "With Puppet loaded" do
module Puppet; end
let(:vardir) { "/var/lib/puppet" }
before :each do
Puppet.expects(:[]).with(:vardir).returns vardir
end
it 'should yield to the block' do
subject.with_puppet { Puppet[:vardir] }
end
it 'should return the nodes vardir' do
subject.with_puppet { Puppet[:vardir] }.should eq vardir
end
end
end
end

View File

@ -0,0 +1,31 @@
#!/usr/bin/env rspec
require 'spec_helper'
describe "the abs function" do
before :all do
Puppet::Parser::Functions.autoloader.loadall
end
before :each do
@scope = Puppet::Parser::Scope.new
end
it "should exist" do
Puppet::Parser::Functions.function("abs").should == "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))
end
it "should convert a negative number into a positive" do
result = @scope.function_abs(["-34"])
result.should(eq(34))
end
it "should do nothing with a positive number" do
result = @scope.function_abs(["5678"])
result.should(eq(5678))
end
end

View File

@ -0,0 +1,31 @@
#!/usr/bin/env rspec
require 'spec_helper'
describe "the bool2num function" do
before :all do
Puppet::Parser::Functions.autoloader.loadall
end
before :each do
@scope = Puppet::Parser::Scope.new
end
it "should exist" do
Puppet::Parser::Functions.function("bool2num").should == "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))
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))
end
end

View File

@ -0,0 +1,26 @@
#!/usr/bin/env rspec
require 'spec_helper'
describe "the capitalize function" do
before :all do
Puppet::Parser::Functions.autoloader.loadall
end
before :each do
@scope = Puppet::Parser::Scope.new
end
it "should exist" do
Puppet::Parser::Functions.function("capitalize").should == "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))
end
it "should capitalize the beginning of a string" do
result = @scope.function_capitalize(["abc"])
result.should(eq("Abc"))
end
end

View File

@ -0,0 +1,26 @@
#!/usr/bin/env rspec
require 'spec_helper'
describe "the chomp function" do
before :all do
Puppet::Parser::Functions.autoloader.loadall
end
before :each do
@scope = Puppet::Parser::Scope.new
end
it "should exist" do
Puppet::Parser::Functions.function("chomp").should == "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))
end
it "should chomp the end of a string" do
result = @scope.function_chomp(["abc\n"])
result.should(eq("abc"))
end
end

View File

@ -0,0 +1,26 @@
#!/usr/bin/env rspec
require 'spec_helper'
describe "the chop function" do
before :all do
Puppet::Parser::Functions.autoloader.loadall
end
before :each do
@scope = Puppet::Parser::Scope.new
end
it "should exist" do
Puppet::Parser::Functions.function("chop").should == "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))
end
it "should chop the end of a string" do
result = @scope.function_chop(["asdf\n"])
result.should(eq("asdf"))
end
end

View File

@ -0,0 +1,26 @@
#!/usr/bin/env rspec
require 'spec_helper'
describe "the delete_at function" do
before :all do
Puppet::Parser::Functions.autoloader.loadall
end
before :each do
@scope = Puppet::Parser::Scope.new
end
it "should exist" do
Puppet::Parser::Functions.function("delete_at").should == "function_delete_at"
end
it "should raise a ParseError if there is less than 1 arguments" do
lambda { @scope.function_delete_at([]) }.should( raise_error(Puppet::ParseError))
end
it "should delete an item at specified location from an array" do
result = @scope.function_delete_at([['a','b','c'],1])
result.should(eq(['a','c']))
end
end

View File

@ -0,0 +1,26 @@
#!/usr/bin/env rspec
require 'spec_helper'
describe "the delete function" do
before :all do
Puppet::Parser::Functions.autoloader.loadall
end
before :each do
@scope = Puppet::Parser::Scope.new
end
it "should exist" do
Puppet::Parser::Functions.function("delete").should == "function_delete"
end
it "should raise a ParseError if there is less than 1 arguments" do
lambda { @scope.function_delete([]) }.should( raise_error(Puppet::ParseError))
end
it "should delete an item from an array" do
result = @scope.function_delete([['a','b','c'],'b'])
result.should(eq(['a','c']))
end
end

View File

@ -0,0 +1,31 @@
#!/usr/bin/env rspec
require 'spec_helper'
describe "the downcase function" do
before :all do
Puppet::Parser::Functions.autoloader.loadall
end
before :each do
@scope = Puppet::Parser::Scope.new
end
it "should exist" do
Puppet::Parser::Functions.function("downcase").should == "function_downcase"
end
it "should raise a ParseError if there is less than 1 arguments" do
lambda { @scope.function_downcase([]) }.should( raise_error(Puppet::ParseError))
end
it "should downcase a string" do
result = @scope.function_downcase(["ASFD"])
result.should(eq("asfd"))
end
it "should do nothing to a string that is already downcase" do
result = @scope.function_downcase(["asdf asdf"])
result.should(eq("asdf asdf"))
end
end

View File

@ -0,0 +1,31 @@
#!/usr/bin/env rspec
require 'spec_helper'
describe "the empty function" do
before :all do
Puppet::Parser::Functions.autoloader.loadall
end
before :each do
@scope = Puppet::Parser::Scope.new
end
it "should exist" do
Puppet::Parser::Functions.function("empty").should == "function_empty"
end
it "should raise a ParseError if there is less than 1 arguments" do
lambda { @scope.function_empty([]) }.should( raise_error(Puppet::ParseError))
end
it "should return a true for an empty string" do
result = @scope.function_empty([''])
result.should(eq(true))
end
it "should return a false for a non-empty string" do
result = @scope.function_empty(['asdf'])
result.should(eq(false))
end
end

View File

@ -0,0 +1,31 @@
#!/usr/bin/env rspec
require 'spec_helper'
describe "the flatten function" do
before :all do
Puppet::Parser::Functions.autoloader.loadall
end
before :each do
@scope = Puppet::Parser::Scope.new
end
it "should exist" do
Puppet::Parser::Functions.function("flatten").should == "function_flatten"
end
it "should raise a ParseError if there is less than 1 arguments" do
lambda { @scope.function_flatten([]) }.should( raise_error(Puppet::ParseError))
end
it "should flatten a complex data structure" do
result = @scope.function_flatten([["a","b",["c",["d","e"],"f","g"]]])
result.should(eq(["a","b","c","d","e","f","g"]))
end
it "should do nothing to a structure that is already flat" do
result = @scope.function_flatten([["a","b","c","d"]])
result.should(eq(["a","b","c","d"]))
end
end

View File

@ -0,0 +1,40 @@
#!/usr/bin/env rspec
require 'spec_helper'
describe "the fqdn_rotate function" do
before :all do
Puppet::Parser::Functions.autoloader.loadall
end
before :each do
@scope = Puppet::Parser::Scope.new
end
it "should exist" do
Puppet::Parser::Functions.function("fqdn_rotate").should == "function_fqdn_rotate"
end
it "should raise a ParseError if there is less than 1 arguments" do
lambda { @scope.function_fqdn_rotate([]) }.should( raise_error(Puppet::ParseError))
end
it "should rotate a string and the result should be the same size" do
@scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1")
result = @scope.function_fqdn_rotate(["asdf"])
result.size.should(eq(4))
end
it "should rotate a string to give the same results for one host" do
@scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1").twice
@scope.function_fqdn_rotate(["abcdefg"]).should eql(@scope.function_fqdn_rotate(["abcdefg"]))
end
it "should rotate a string to give different values on different hosts" do
@scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1")
val1 = @scope.function_fqdn_rotate(["abcdefghijklmnopqrstuvwxyz01234567890987654321"])
@scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.2")
val2 = @scope.function_fqdn_rotate(["abcdefghijklmnopqrstuvwxyz01234567890987654321"])
val1.should_not eql(val2)
end
end

View File

@ -0,0 +1,42 @@
#!/usr/bin/env rspec
require 'puppet'
require 'fileutils'
require 'spec_helper'
describe Puppet::Parser::Functions.function(:get_module_path) do
include PuppetlabsSpec::Files
def get_scope(environment = 'production')
scope = Puppet::Parser::Scope.new
scope.compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("floppy", :environment => environment))
scope
end
it 'should only allow one argument' do
expect { get_scope.function_get_module_path([]) }.should raise_error(Puppet::ParseError, /Wrong number of arguments, expects one/)
expect { get_scope.function_get_module_path(['1','2','3']) }.should raise_error(Puppet::ParseError, /Wrong number of arguments, expects one/)
end
it 'should raise an exception when the module cannot be found' do
expect { get_scope.function_get_module_path(['foo']) }.should raise_error(Puppet::ParseError, /Could not find module/)
end
describe 'when locating a module' do
let(:modulepath) { tmpdir('modulepath') }
let(:foo_path) { File.join(modulepath, 'foo') }
before(:each) { FileUtils.mkdir(foo_path) }
it 'should be able to find module paths from the modulepath setting' do
Puppet[:modulepath] = modulepath
get_scope.function_get_module_path(['foo']).should == foo_path
end
it 'should be able to find module paths when the modulepath is a list' do
Puppet[:modulepath] = modulepath + ":/tmp"
get_scope.function_get_module_path(['foo']).should == foo_path
end
it 'should be able to find module paths from the environment' do
conf_file = tmpfilename('conffile')
File.open(conf_file, 'w') do |fh|
fh.write("[dansenvironment]\nmodulepath = #{modulepath}")
end
Puppet[:config] = conf_file
Puppet.parse_config
get_scope('dansenvironment').function_get_module_path(['foo']).should ==foo_path
end
end
end

View File

@ -0,0 +1,53 @@
require 'puppet'
# We don't need this for the basic tests we're doing
# require 'spec_helper'
# Dan mentioned that Nick recommended the function method call
# to return the string value for the test description.
# this will not even try the test if the function cannot be
# loaded.
describe Puppet::Parser::Functions.function(:getvar) do
# Pulled from Dan's create_resources function
def get_scope
@topscope = Puppet::Parser::Scope.new
# This is necessary so we don't try to use the compiler to discover our parent.
@topscope.parent = nil
@scope = Puppet::Parser::Scope.new
@scope.compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("floppy", :environment => 'production'))
@scope.parent = @topscope
@compiler = @scope.compiler
end
describe 'when calling getvar from puppet' do
it "should not compile when no arguments are passed" do
Puppet[:code] = 'getvar()'
get_scope
expect { @scope.compiler.compile }.should raise_error(Puppet::ParseError, /wrong number of arguments/)
end
it "should not compile when too many arguments are passed" do
Puppet[:code] = 'getvar("foo::bar", "baz")'
get_scope
expect { @scope.compiler.compile }.should raise_error(Puppet::ParseError, /wrong number of arguments/)
end
it "should lookup variables in other namespaces" do
pending "Puppet doesn't appear to think getvar is an rvalue function... BUG?"
Puppet[:code] = <<-'ENDofPUPPETcode'
class site::data { $foo = 'baz' }
include site::data
$foo = getvar("site::data::foo")
if $foo != 'baz' {
fail('getvar did not return what we expect')
}
ENDofPUPPETcode
get_scope
@scope.compiler.compile
end
end
end

View File

@ -0,0 +1,26 @@
#!/usr/bin/env rspec
require 'spec_helper'
describe "the grep function" do
before :all do
Puppet::Parser::Functions.autoloader.loadall
end
before :each do
@scope = Puppet::Parser::Scope.new
end
it "should exist" do
Puppet::Parser::Functions.function("grep").should == "function_grep"
end
it "should raise a ParseError if there is less than 1 arguments" do
lambda { @scope.function_grep([]) }.should( raise_error(Puppet::ParseError))
end
it "should grep contents from an array" do
result = @scope.function_grep([["aaabbb","bbbccc","dddeee"], "bbb"])
result.should(eq(["aaabbb","bbbccc"]))
end
end

View File

@ -0,0 +1,46 @@
require 'puppet'
require 'mocha'
describe Puppet::Parser::Functions.function(:has_key) do
# Pulled from Dan's create_resources function
# TODO - this should be moved to spec_helper since the
# logic is likely to be applied to multiple rspec files.
let(:compiler) {
topscope = Puppet::Parser::Scope.new
# This is necessary so we don't try to use the compiler to discover our parent.
topscope.parent = nil
my_scope = Puppet::Parser::Scope.new
my_scope.compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("floppy", :environment => 'production'))
my_scope.parent = topscope
compiler = my_scope.compiler
}
let(:scope) {
scope = Puppet::Parser::Scope.new
scope.stubs(:environment).returns(Puppet::Node::Environment.new('production'))
scope
}
describe 'when calling has_key from puppet' do
it "should not compile when no arguments are passed" do
Puppet[:code] = 'has_key()'
expect { compiler.compile }.should raise_error(Puppet::ParseError, /wrong number of arguments/)
end
it "should not compile when 1 argument is passed" do
Puppet[:code] = "has_key('foo')"
expect { compiler.compile }.should raise_error(Puppet::ParseError, /wrong number of arguments/)
end
it "should require the first value to be a Hash" do
Puppet[:code] = "has_key('foo', 'bar')"
expect { compiler.compile }.should raise_error(Puppet::ParseError, /expects the first argument to be a hash/)
end
end
describe 'when calling the function has_key from a scope instance' do
it 'should detect existing keys' do
scope.function_has_key([{'one' => 1}, 'one']).should be_true
end
it 'should detect existing keys' do
scope.function_has_key([{'one' => 1}, 'two']).should be_false
end
end
end

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