summaryrefslogtreecommitdiffstats
path: root/lib/puppet/parser/functions
diff options
context:
space:
mode:
authorDominic Cleal <dcleal@redhat.com>2010-11-27 13:36:04 +0000
committerDominic Cleal <dcleal@redhat.com>2010-11-27 13:36:04 +0000
commitafe2d014feb2210a8666c93465d11e9c9d555f8b (patch)
tree208f5ac82b2c29610d2021821c8fca9b079e638b /lib/puppet/parser/functions
parent143fc744a839affd328234fca26246d49d15d3d8 (diff)
parent4b35402ba85d8842d757becec5c8a7bf4d6f6654 (diff)
downloadpuppet-afe2d014feb2210a8666c93465d11e9c9d555f8b.tar.gz
puppet-afe2d014feb2210a8666c93465d11e9c9d555f8b.tar.xz
puppet-afe2d014feb2210a8666c93465d11e9c9d555f8b.zip
Merge branch 'master' of github.com:domcleal/puppet into master-old
Diffstat (limited to 'lib/puppet/parser/functions')
-rw-r--r--lib/puppet/parser/functions/defined.rb2
-rw-r--r--lib/puppet/parser/functions/extlookup.rb157
-rw-r--r--lib/puppet/parser/functions/file.rb2
-rw-r--r--lib/puppet/parser/functions/inline_template.rb11
-rw-r--r--lib/puppet/parser/functions/md5.rb5
-rw-r--r--lib/puppet/parser/functions/realize.rb2
-rw-r--r--lib/puppet/parser/functions/regsubst.rb38
-rw-r--r--lib/puppet/parser/functions/require.rb5
-rw-r--r--lib/puppet/parser/functions/split.rb2
-rw-r--r--lib/puppet/parser/functions/sprintf.rb2
-rw-r--r--lib/puppet/parser/functions/template.rb6
-rw-r--r--lib/puppet/parser/functions/versioncmp.rb24
12 files changed, 210 insertions, 46 deletions
diff --git a/lib/puppet/parser/functions/defined.rb b/lib/puppet/parser/functions/defined.rb
index 2930a65cc..90632af2f 100644
--- a/lib/puppet/parser/functions/defined.rb
+++ b/lib/puppet/parser/functions/defined.rb
@@ -3,7 +3,7 @@ Puppet::Parser::Functions::newfunction(:defined, :type => :rvalue, :doc => "Dete
type is defined, either as a native type or a defined type, or whether a class is defined.
This is useful for checking whether a class is defined and only including it if it is.
This function can also test whether a resource has been defined, using resource references
- (e.g., ``if defined(File['/tmp/myfile']) { ... }``). This function is unfortunately
+ (e.g., `if defined(File['/tmp/myfile']) { ... }`). This function is unfortunately
dependent on the parse order of the configuration when testing whether a resource is defined.") do |vals|
result = false
vals = [vals] unless vals.is_a?(Array)
diff --git a/lib/puppet/parser/functions/extlookup.rb b/lib/puppet/parser/functions/extlookup.rb
new file mode 100644
index 000000000..bc55410b9
--- /dev/null
+++ b/lib/puppet/parser/functions/extlookup.rb
@@ -0,0 +1,157 @@
+require 'csv'
+
+module Puppet::Parser::Functions
+ newfunction(:extlookup,
+ :type => :rvalue,
+ :doc => "This is a parser function to read data from external files, this version
+uses CSV files but the concept can easily be adjust for databases, yaml
+or any other queryable data source.
+
+The object of this is to make it obvious when it's being used, rather than
+magically loading data in when an module is loaded I prefer to look at the code
+and see statements like:
+
+ $snmp_contact = extlookup(\"snmp_contact\")
+
+The above snippet will load the snmp_contact value from CSV files, this in its
+own is useful but a common construct in puppet manifests is something like this:
+
+ case $domain {
+ \"myclient.com\": { $snmp_contact = \"John Doe <john@myclient.com>\" }
+ default: { $snmp_contact = \"My Support <support@my.com>\" }
+ }
+
+Over time there will be a lot of this kind of thing spread all over your manifests
+and adding an additional client involves grepping through manifests to find all the
+places where you have constructs like this.
+
+This is a data problem and shouldn't be handled in code, a using this function you
+can do just that.
+
+First you configure it in site.pp:
+
+ $extlookup_datadir = \"/etc/puppet/manifests/extdata\"
+ $extlookup_precedence = [\"%{fqdn}\", \"domain_%{domain}\", \"common\"]
+
+The array tells the code how to resolve values, first it will try to find it in
+web1.myclient.com.csv then in domain_myclient.com.csv and finally in common.csv
+
+Now create the following data files in /etc/puppet/manifests/extdata:
+
+ domain_myclient.com.csv:
+ snmp_contact,John Doe <john@myclient.com>
+ root_contact,support@%{domain}
+ client_trusted_ips,192.168.1.130,192.168.10.0/24
+
+ common.csv:
+ snmp_contact,My Support <support@my.com>
+ root_contact,support@my.com
+
+Now you can replace the case statement with the simple single line to achieve
+the exact same outcome:
+
+ $snmp_contact = extlookup(\"snmp_contact\")
+
+The above code shows some other features, you can use any fact or variable that
+is in scope by simply using %{varname} in your data files, you can return arrays
+by just having multiple values in the csv after the initial variable name.
+
+In the event that a variable is nowhere to be found a critical error will be raised
+that will prevent your manifest from compiling, this is to avoid accidentally putting
+in empty values etc. You can however specify a default value:
+
+ $ntp_servers = extlookup(\"ntp_servers\", \"1.${country}.pool.ntp.org\")
+
+In this case it will default to \"1.${country}.pool.ntp.org\" if nothing is defined in
+any data file.
+
+You can also specify an additional data file to search first before any others at use
+time, for example:
+
+ $version = extlookup(\"rsyslog_version\", \"present\", \"packages\")
+ package{\"rsyslog\": ensure => $version }
+
+This will look for a version configured in packages.csv and then in the rest as configured
+by $extlookup_precedence if it's not found anywhere it will default to `present`, this kind
+of use case makes puppet a lot nicer for managing large amounts of packages since you do not
+need to edit a load of manifests to do simple things like adjust a desired version number.
+
+Precedence values can have variables embedded in them in the form %{fqdn}, you could for example do:
+
+ $extlookup_precedence = [\"hosts/%{fqdn}\", \"common\"]
+
+This will result in /path/to/extdata/hosts/your.box.com.csv being searched.
+
+This is for back compatibility to interpolate variables with %. % interpolation is a workaround for a problem that has been fixed: Puppet variable interpolation at top scope used to only happen on each run.") do |args|
+
+ key = args[0]
+
+ default = args[1]
+ datafile = args[2]
+
+ raise Puppet::ParseError, ("extlookup(): wrong number of arguments (#{args.length}; must be <= 3)") if args.length > 3
+
+ extlookup_datadir = lookupvar('extlookup_datadir')
+ extlookup_precedence = Array.new
+
+ extlookup_precedence = lookupvar('extlookup_precedence').collect do |var|
+ var.gsub(/%\{(.+?)\}/) do |capture|
+ lookupvar($1)
+ end
+ end
+
+ datafiles = Array.new
+
+ # if we got a custom data file, put it first in the array of search files
+ if datafile != ""
+ datafiles << extlookup_datadir + "/#{datafile}.csv" if File.exists?(extlookup_datadir + "/#{datafile}.csv")
+ end
+
+ extlookup_precedence.each do |d|
+ datafiles << extlookup_datadir + "/#{d}.csv"
+ end
+
+ desired = nil
+
+ datafiles.each do |file|
+ if desired.nil?
+ if File.exists?(file)
+ result = CSV.read(file).find_all do |r|
+ r[0] == key
+ end
+
+ # return just the single result if theres just one,
+ # else take all the fields in the csv and build an array
+ if result.length > 0
+ if result[0].length == 2
+ val = result[0][1].to_s
+
+ # parse %{}'s in the CSV into local variables using lookupvar()
+ while val =~ /%\{(.+?)\}/
+ val.gsub!(/%\{#{$1}\}/, lookupvar($1))
+ end
+
+ desired = val
+ elsif result[0].length > 1
+ length = result[0].length
+ cells = result[0][1,length]
+
+ # Individual cells in a CSV result are a weird data type and throws
+ # puppets yaml parsing, so just map it all to plain old strings
+ desired = cells.map do |c|
+ # parse %{}'s in the CSV into local variables using lookupvar()
+ while c =~ /%\{(.+?)\}/
+ c.gsub!(/%\{#{$1}\}/, lookupvar($1))
+ end
+
+ c.to_s
+ end
+ end
+ end
+ end
+ end
+ end
+
+ desired || default or raise Puppet::ParseError, "No match found for '#{key}' in any data file during extlookup()"
+ end
+end
diff --git a/lib/puppet/parser/functions/file.rb b/lib/puppet/parser/functions/file.rb
index 963111260..19ab9ba2e 100644
--- a/lib/puppet/parser/functions/file.rb
+++ b/lib/puppet/parser/functions/file.rb
@@ -2,7 +2,7 @@
Puppet::Parser::Functions::newfunction(
:file, :type => :rvalue,
-
+
:doc => "Return the contents of a file. Multiple files
can be passed, and the first file that exists will be read in.") do |vals|
ret = nil
diff --git a/lib/puppet/parser/functions/inline_template.rb b/lib/puppet/parser/functions/inline_template.rb
index 46e000383..9759ff6e1 100644
--- a/lib/puppet/parser/functions/inline_template.rb
+++ b/lib/puppet/parser/functions/inline_template.rb
@@ -1,9 +1,10 @@
Puppet::Parser::Functions::newfunction(:inline_template, :type => :rvalue, :doc =>
- "Evaluate a template string and return its value. See `the templating docs
- <http://docs.puppetlabs.com/guides/templating.html>`_ for more information. Note that
- if multiple template strings are specified, their output is all concatenated
- and returned as the output of the function.") do |vals|
- require 'erb'
+ "Evaluate a template string and return its value. See
+ [the templating docs](http://docs.puppetlabs.com/guides/templating.html) for
+ more information. Note that if multiple template strings are specified, their
+ output is all concatenated and returned as the output of the function.") do |vals|
+
+ require 'erb'
vals.collect do |string|
# Use a wrapper, so the template can't get access to the full
diff --git a/lib/puppet/parser/functions/md5.rb b/lib/puppet/parser/functions/md5.rb
new file mode 100644
index 000000000..f7a4f7222
--- /dev/null
+++ b/lib/puppet/parser/functions/md5.rb
@@ -0,0 +1,5 @@
+Puppet::Parser::Functions::newfunction(:md5, :type => :rvalue, :doc => "Returns a MD5 hash value from a provided string.") do |args|
+ require 'md5'
+
+ Digest::MD5.hexdigest(args[0])
+end
diff --git a/lib/puppet/parser/functions/realize.rb b/lib/puppet/parser/functions/realize.rb
index 4247b8af8..c21ccd14a 100644
--- a/lib/puppet/parser/functions/realize.rb
+++ b/lib/puppet/parser/functions/realize.rb
@@ -5,7 +5,7 @@ Puppet::Parser::Functions::newfunction(:realize, :doc => "Make a virtual object
when you want to know the name of the virtual object and don't want to
bother with a full collection. It is slightly faster than a collection,
and, of course, is a bit shorter. You must pass the object using a
- reference; e.g.: ``realize User[luke]``." ) do |vals|
+ reference; e.g.: `realize User[luke]`." ) do |vals|
coll = Puppet::Parser::Collector.new(self, :nomatter, nil, nil, :virtual)
vals = [vals] unless vals.is_a?(Array)
coll.resources = vals.flatten
diff --git a/lib/puppet/parser/functions/regsubst.rb b/lib/puppet/parser/functions/regsubst.rb
index c0aeef222..f655db7b3 100644
--- a/lib/puppet/parser/functions/regsubst.rb
+++ b/lib/puppet/parser/functions/regsubst.rb
@@ -6,37 +6,37 @@ module Puppet::Parser::Functions
:doc => "
Perform regexp replacement on a string or array of strings.
-- **Parameters** (in order):
+* *Parameters* (in order):
-:target: The string or array of strings to operate on. If an array, the replacement will be performed on each of the elements in the array, and the return value will be an array.
+ _target_ The string or array of strings to operate on. If an array, the replacement will be performed on each of the elements in the array, and the return value will be an array.
-:regexp: The regular expression matching the target string. If you want it anchored at the start and or end of the string, you must do that with ^ and $ yourself.
+ _regexp_ The regular expression matching the target string. If you want it anchored at the start and or end of the string, you must do that with ^ and $ yourself.
-:replacement: Replacement string. Can contain back references to what was matched using \\0, \\1, and so on.
+ _replacement_ Replacement string. Can contain back references to what was matched using \\0, \\1, and so on.
-:flags: Optional. String of single letter flags for how the regexp is interpreted:
+ _flags_ Optional. String of single letter flags for how the regexp is interpreted:
- - **E** Extended regexps
- - **I** Ignore case in regexps
- - **M** Multiline regexps
- - **G** Global replacement; all occurrences of the regexp in each target string will be replaced. Without this, only the first occurrence will be replaced.
+ - *E* Extended regexps
+ - *I* Ignore case in regexps
+ - *M* Multiline regexps
+ - *G* Global replacement; all occurrences of the regexp in each target string will be replaced. Without this, only the first occurrence will be replaced.
-:lang: Optional. How to handle multibyte characters. A single-character string with the following values:
+ _lang_ Optional. How to handle multibyte characters. A single-character string with the following values:
- - **N** None
- - **E** EUC
- - **S** SJIS
- - **U** UTF-8
+ - *N* None
+ - *E* EUC
+ - *S* SJIS
+ - *U* UTF-8
-- **Examples**
+* *Examples*
-Get the third octet from the node's IP address::
+Get the third octet from the node's IP address:
- $i3 = regsubst($ipaddress,'^([0-9]+)[.]([0-9]+)[.]([0-9]+)[.]([0-9]+)$','\\3')
+ $i3 = regsubst($ipaddress,'^([0-9]+)[.]([0-9]+)[.]([0-9]+)[.]([0-9]+)$','\\3')
-Put angle brackets around each octet in the node's IP address::
+Put angle brackets around each octet in the node's IP address:
- $x = regsubst($ipaddress, '([0-9]+)', '<\\1>', 'G')
+ $x = regsubst($ipaddress, '([0-9]+)', '<\\1>', 'G')
") \
do |args|
unless args.length.between?(3, 5)
diff --git a/lib/puppet/parser/functions/require.rb b/lib/puppet/parser/functions/require.rb
index 3f98c9523..64285307e 100644
--- a/lib/puppet/parser/functions/require.rb
+++ b/lib/puppet/parser/functions/require.rb
@@ -12,9 +12,8 @@ relationships between classes. This function is a superset of the
class depends on the required class.
Warning: using require in place of include can lead to unwanted dependency cycles.
- For instance the following manifest, with 'require' instead of 'include'
- would produce a nasty dependence cycle, because notify imposes a before
- between File[/foo] and Service[foo]::
+
+For instance the following manifest, with 'require' instead of 'include' would produce a nasty dependence cycle, because notify imposes a before between File[/foo] and Service[foo]:
class myservice {
service { foo: ensure => running }
diff --git a/lib/puppet/parser/functions/split.rb b/lib/puppet/parser/functions/split.rb
index 5d0a9dabc..52394095a 100644
--- a/lib/puppet/parser/functions/split.rb
+++ b/lib/puppet/parser/functions/split.rb
@@ -6,7 +6,7 @@ module Puppet::Parser::Functions
:doc => "\
Split a string variable into an array using the specified split regexp.
- Usage::
+ Usage:
$string = 'v1.v2:v3.v4'
$array_var1 = split($string, ':')
diff --git a/lib/puppet/parser/functions/sprintf.rb b/lib/puppet/parser/functions/sprintf.rb
index 5ada0fed7..5eb4a4f9d 100644
--- a/lib/puppet/parser/functions/sprintf.rb
+++ b/lib/puppet/parser/functions/sprintf.rb
@@ -5,7 +5,7 @@ module Puppet::Parser::Functions
:doc => "Perform printf-style formatting of text.
- The first parameter is format string describing how the rest of the parameters should be formatted. See the documentation for the ``Kernel::sprintf`` function in Ruby for all the details.") do |args|
+ The first parameter is format string describing how the rest of the parameters should be formatted. See the documentation for the `Kernel::sprintf` function in Ruby for all the details.") do |args|
raise Puppet::ParseError, 'sprintf() needs at least one argument' if args.length < 1
fmt = args.shift
return sprintf(fmt, *args)
diff --git a/lib/puppet/parser/functions/template.rb b/lib/puppet/parser/functions/template.rb
index f51bcc1e2..6fa110332 100644
--- a/lib/puppet/parser/functions/template.rb
+++ b/lib/puppet/parser/functions/template.rb
@@ -1,6 +1,8 @@
Puppet::Parser::Functions::newfunction(:template, :type => :rvalue, :doc =>
- "Evaluate a template and return its value. See `the templating docs
- <http://docs.puppetlabs.com/guides/templating.html>`_ for more information.
+ "Evaluate a template and return its value. See
+ [the templating docs](http://docs.puppetlabs.com/guides/templating.html) for
+ more information.
+
Note that if multiple templates are specified, their output is all
concatenated and returned as the output of the function.") do |vals|
require 'erb'
diff --git a/lib/puppet/parser/functions/versioncmp.rb b/lib/puppet/parser/functions/versioncmp.rb
index b38406532..6091e0923 100644
--- a/lib/puppet/parser/functions/versioncmp.rb
+++ b/lib/puppet/parser/functions/versioncmp.rb
@@ -3,26 +3,26 @@ require 'puppet/util/package'
Puppet::Parser::Functions::newfunction(
:versioncmp, :type => :rvalue,
-
+
:doc => "Compares two versions
-Prototype::
+Prototype:
- \$result = versioncmp(a, b)
+ \$result = versioncmp(a, b)
- where a and b are arbitrary version strings
+Where a and b are arbitrary version strings
-This functions returns a number::
+This functions returns a number:
- * > 0 if version a is greater than version b
- * == 0 if both version are equals
- * < 0 if version a is less than version b
+* Greater than 0 if version a is greater than version b
+* Equal to 0 if both version are equals
+* Less than 0 if version a is less than version b
-Example::
+Example:
- if versioncmp('2.6-1', '2.4.5') > 0 {
- notice('2.6-1 is > than 2.4.5')
- }
+ if versioncmp('2.6-1', '2.4.5') > 0 {
+ notice('2.6-1 is > than 2.4.5')
+ }
") do |args|