summaryrefslogtreecommitdiff
path: root/lib/puppet
diff options
context:
space:
mode:
Diffstat (limited to 'lib/puppet')
-rw-r--r--lib/puppet/functions/fact.rb58
-rw-r--r--lib/puppet/functions/to_json.rb21
-rw-r--r--lib/puppet/functions/to_json_pretty.rb21
-rw-r--r--lib/puppet/functions/to_yaml.rb21
-rw-r--r--lib/puppet/parser/functions/pw_hash.rb7
-rw-r--r--lib/puppet/parser/functions/round.rb33
-rw-r--r--lib/puppet/parser/functions/unique.rb4
-rw-r--r--lib/puppet/parser/functions/validate_domain_name.rb39
-rw-r--r--lib/puppet/provider/file_line/ruby.rb106
-rw-r--r--lib/puppet/type/file_line.rb8
10 files changed, 268 insertions, 50 deletions
diff --git a/lib/puppet/functions/fact.rb b/lib/puppet/functions/fact.rb
new file mode 100644
index 0000000..dfb048b
--- /dev/null
+++ b/lib/puppet/functions/fact.rb
@@ -0,0 +1,58 @@
+# Digs into the facts hash using dot-notation
+#
+# Example usage:
+#
+# fact('osfamily')
+# fact('os.architecture')
+#
+# Array indexing:
+#
+# fact('mountpoints."/dev".options.1')
+#
+# Fact containing a "." in the name:
+#
+# fact('vmware."VRA.version"')
+#
+Puppet::Functions.create_function(:fact) do
+ dispatch :fact do
+ param 'String', :fact_name
+ end
+
+ def to_dot_syntax(array_path)
+ array_path.map do |string|
+ string.include?('.') ? %Q{"#{string}"} : string
+ end.join('.')
+ end
+
+ def fact(fact_name)
+ facts = closure_scope['facts']
+
+ # Transform the dot-notation string into an array of paths to walk. Make
+ # sure to correctly extract double-quoted values containing dots as single
+ # elements in the path.
+ path = fact_name.scan(/([^."]+)|(?:")([^"]+)(?:")/).map {|x| x.compact.first }
+
+ walked_path = []
+ path.reduce(facts) do |d, k|
+ return nil if d.nil? || k.nil?
+
+ case
+ when d.is_a?(Array)
+ begin
+ result = d[Integer(k)]
+ rescue ArgumentError => e
+ Puppet.warning("fact request for #{fact_name} returning nil: '#{to_dot_syntax(walked_path)}' is an array; cannot index to '#{k}'")
+ result = nil
+ end
+ when d.is_a?(Hash)
+ result = d[k]
+ else
+ Puppet.warning("fact request for #{fact_name} returning nil: '#{to_dot_syntax(walked_path)}' is not a collection; cannot walk to '#{k}'")
+ result = nil
+ end
+
+ walked_path << k
+ result
+ end
+ end
+end
diff --git a/lib/puppet/functions/to_json.rb b/lib/puppet/functions/to_json.rb
new file mode 100644
index 0000000..782d695
--- /dev/null
+++ b/lib/puppet/functions/to_json.rb
@@ -0,0 +1,21 @@
+# Take a data structure and output it as JSON
+#
+# @example how to output JSON
+# # output json to a file
+# file { '/tmp/my.json':
+# ensure => file,
+# content => to_json($myhash),
+# }
+#
+#
+require 'json'
+
+Puppet::Functions.create_function(:to_json) do
+ dispatch :to_json do
+ param 'Any', :data
+ end
+
+ def to_json(data)
+ data.to_json
+ end
+end
diff --git a/lib/puppet/functions/to_json_pretty.rb b/lib/puppet/functions/to_json_pretty.rb
new file mode 100644
index 0000000..4c28539
--- /dev/null
+++ b/lib/puppet/functions/to_json_pretty.rb
@@ -0,0 +1,21 @@
+# Take a data structure and output it as pretty JSON
+#
+# @example how to output pretty JSON
+# # output pretty json to a file
+# file { '/tmp/my.json':
+# ensure => file,
+# content => to_json_pretty($myhash),
+# }
+#
+#
+require 'json'
+
+Puppet::Functions.create_function(:to_json_pretty) do
+ dispatch :to_json_pretty do
+ param 'Variant[Hash, Array]', :data
+ end
+
+ def to_json_pretty(data)
+ JSON.pretty_generate(data)
+ end
+end
diff --git a/lib/puppet/functions/to_yaml.rb b/lib/puppet/functions/to_yaml.rb
new file mode 100644
index 0000000..fdd7370
--- /dev/null
+++ b/lib/puppet/functions/to_yaml.rb
@@ -0,0 +1,21 @@
+# Take a data structure and output it as YAML
+#
+# @example how to output YAML
+# # output yaml to a file
+# file { '/tmp/my.yaml':
+# ensure => file,
+# content => to_yaml($myhash),
+# }
+#
+#
+require 'yaml'
+
+Puppet::Functions.create_function(:to_yaml) do
+ dispatch :to_yaml do
+ param 'Any', :data
+ end
+
+ def to_yaml(data)
+ data.to_yaml
+ end
+end
diff --git a/lib/puppet/parser/functions/pw_hash.rb b/lib/puppet/parser/functions/pw_hash.rb
index d99ee5b..adcc719 100644
--- a/lib/puppet/parser/functions/pw_hash.rb
+++ b/lib/puppet/parser/functions/pw_hash.rb
@@ -27,6 +27,13 @@ Puppet::Parser::Functions::newfunction(
environment contains several different operating systems, ensure that they
are compatible before using this function.") do |args|
raise ArgumentError, "pw_hash(): wrong number of arguments (#{args.size} for 3)" if args.size != 3
+ args.map! do |arg|
+ if (defined? Puppet::Pops::Types::PSensitiveType::Sensitive) && (arg.is_a? Puppet::Pops::Types::PSensitiveType::Sensitive)
+ arg.unwrap
+ else
+ arg
+ end
+ end
raise ArgumentError, "pw_hash(): first argument must be a string" unless args[0].is_a? String or args[0].nil?
raise ArgumentError, "pw_hash(): second argument must be a string" unless args[1].is_a? String
hashes = { 'md5' => '1',
diff --git a/lib/puppet/parser/functions/round.rb b/lib/puppet/parser/functions/round.rb
new file mode 100644
index 0000000..489c301
--- /dev/null
+++ b/lib/puppet/parser/functions/round.rb
@@ -0,0 +1,33 @@
+#
+# round.rb
+#
+
+module Puppet::Parser::Functions
+ newfunction(:round, :type => :rvalue, :doc => <<-EOS
+ Rounds a number to the nearest integer
+
+ *Examples:*
+
+ round(2.9)
+
+ returns: 3
+
+ round(2.4)
+
+ returns: 2
+
+ EOS
+ ) do |args|
+
+ raise Puppet::ParseError, "round(): Wrong number of arguments given #{args.size} for 1" if args.size != 1
+ raise Puppet::ParseError, "round(): Expected a Numeric, got #{args[0].class}" unless args[0].is_a? Numeric
+
+ value = args[0]
+
+ if value >= 0
+ Integer(value + 0.5)
+ else
+ Integer(value - 0.5)
+ end
+ end
+end
diff --git a/lib/puppet/parser/functions/unique.rb b/lib/puppet/parser/functions/unique.rb
index b57431d..1e2a895 100644
--- a/lib/puppet/parser/functions/unique.rb
+++ b/lib/puppet/parser/functions/unique.rb
@@ -24,6 +24,10 @@ This returns:
EOS
) do |arguments|
+ if Puppet::Util::Package.versioncmp(Puppet.version, '5.0.0') >= 0
+ function_deprecation([:unique, 'This method is deprecated, please use the core puppet unique function. There is further documentation for the function in the release notes of Puppet 5.0.'])
+ end
+
raise(Puppet::ParseError, "unique(): Wrong number of arguments given (#{arguments.size} for 1)") if arguments.size < 1
value = arguments[0]
diff --git a/lib/puppet/parser/functions/validate_domain_name.rb b/lib/puppet/parser/functions/validate_domain_name.rb
new file mode 100644
index 0000000..c3fad78
--- /dev/null
+++ b/lib/puppet/parser/functions/validate_domain_name.rb
@@ -0,0 +1,39 @@
+module Puppet::Parser::Functions
+ newfunction(:validate_domain_name, :doc => <<-ENDHEREDOC
+ Validate that all values passed are syntactically correct domain names.
+ Fail compilation if any value fails this check.
+
+ The following values will pass:
+
+ $my_domain_name = 'server.domain.tld'
+ validate_domain_name($my_domain_name)
+ validate_domain_name('domain.tld', 'puppet.com', $my_domain_name)
+
+ The following values will fail, causing compilation to abort:
+
+ validate_domain_name(1)
+ validate_domain_name(true)
+ validate_domain_name('invalid domain')
+ validate_domain_name('-foo.example.com')
+ validate_domain_name('www.example.2com')
+
+ ENDHEREDOC
+ ) do |args|
+
+ rescuable_exceptions = [ArgumentError]
+
+ if args.empty?
+ raise Puppet::ParseError, "validate_domain_name(): wrong number of arguments (#{args.length}; must be > 0)"
+ end
+
+ args.each do |arg|
+ raise Puppet::ParseError, "#{arg.inspect} is not a string." unless arg.is_a?(String)
+
+ begin
+ raise Puppet::ParseError, "#{arg.inspect} is not a syntactically correct domain name" unless function_is_domain_name([arg])
+ rescue *rescuable_exceptions
+ raise Puppet::ParseError, "#{arg.inspect} is not a syntactically correct domain name"
+ end
+ end
+ end
+end
diff --git a/lib/puppet/provider/file_line/ruby.rb b/lib/puppet/provider/file_line/ruby.rb
index 1d27424..16f2709 100644
--- a/lib/puppet/provider/file_line/ruby.rb
+++ b/lib/puppet/provider/file_line/ruby.rb
@@ -1,37 +1,42 @@
Puppet::Type.type(:file_line).provide(:ruby) do
def exists?
- found = true
- if resource[:replace].to_s != 'true' and count_matches(match_regex) > 0
- found = true
+ found = false
+ lines_count = 0
+ lines.each do |line|
+ found = line.chomp == resource[:line]
+ if found
+ lines_count += 1
+ end
+ end
+ if resource[:match] == nil
+ found = lines_count > 0
else
- lines.find do |line|
- if resource[:ensure].to_s == 'absent' and resource[:match_for_absence].to_s == 'true'
- found = line.chomp =~ Regexp.new(resource[:match])
- else
- found = line.chomp == resource[:line].chomp
- end
- if found == false then
- break
- end
+ match_count = count_matches(new_match_regex)
+ if resource[:append_on_no_match].to_s == 'false'
+ found = true
+ elsif resource[:replace].to_s == 'true'
+ found = lines_count > 0 && lines_count == match_count
+ else
+ found = match_count > 0
end
end
found
end
def create
- unless resource[:replace].to_s != 'true' and count_matches(match_regex) > 0
+ unless resource[:replace].to_s != 'true' && count_matches(new_match_regex) > 0
if resource[:match]
handle_create_with_match
elsif resource[:after]
handle_create_with_after
else
- append_line
+ handle_append_line
end
end
end
def destroy
- if resource[:match_for_absence].to_s == 'true' and resource[:match]
+ if resource[:match_for_absence].to_s == 'true' && resource[:match]
handle_destroy_with_match
else
handle_destroy_line
@@ -39,6 +44,7 @@ Puppet::Type.type(:file_line).provide(:ruby) do
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
@@ -53,25 +59,34 @@ Puppet::Type.type(:file_line).provide(:ruby) do
end
end
- def match_regex
+ def new_after_regex
+ resource[:after] ? Regexp.new(resource[:after]) : nil
+ end
+
+ def new_match_regex
resource[:match] ? Regexp.new(resource[:match]) : nil
end
+ def count_matches(regex)
+ lines.select{ |line| line.match(regex) }.size
+ end
+
def handle_create_with_match()
- regex_after = resource[:after] ? Regexp.new(resource[:after]) : nil
- match_count = count_matches(match_regex)
+ after_regex = new_after_regex
+ match_regex = new_match_regex
+ match_count = count_matches(new_match_regex)
if match_count > 1 && resource[:multiple].to_s != 'true'
raise Puppet::Error, "More than one line in file '#{resource[:path]}' matches pattern '#{resource[:match]}'"
end
File.open(resource[:path], 'w') do |fh|
- lines.each do |l|
- fh.puts(match_regex.match(l) ? resource[:line] : l)
- if (match_count == 0 and regex_after)
- if regex_after.match(l)
+ lines.each do |line|
+ fh.puts(match_regex.match(line) ? resource[:line] : line)
+ if match_count == 0 && after_regex
+ if after_regex.match(line)
fh.puts(resource[:line])
- match_count += 1 #Increment match_count to indicate that the new line has been inserted.
+ match_count += 1 # Increment match_count to indicate that the new line has been inserted.
end
end
end
@@ -83,32 +98,29 @@ Puppet::Type.type(:file_line).provide(:ruby) do
end
def handle_create_with_after
- regex = Regexp.new(resource[:after])
- count = count_matches(regex)
+ after_regex = new_after_regex
+ after_count = count_matches(after_regex)
- if count > 1 && resource[:multiple].to_s != 'true'
- raise Puppet::Error, "#{count} lines match pattern '#{resource[:after]}' in file '#{resource[:path]}'. One or no line must match the pattern."
+ if after_count > 1 && resource[:multiple].to_s != 'true'
+ raise Puppet::Error, "#{after_count} lines match pattern '#{resource[:after]}' in file '#{resource[:path]}'. One or no line must match the pattern."
end
- File.open(resource[:path], 'w') do |fh|
- lines.each do |l|
- fh.puts(l)
- if regex.match(l) then
+ File.open(resource[:path],'w') do |fh|
+ lines.each do |line|
+ fh.puts(line)
+ if after_regex.match(line)
fh.puts(resource[:line])
end
end
- end
- if (count == 0) # append the line to the end of the file
- append_line
+ if (after_count == 0)
+ fh.puts(resource[:line])
+ end
end
end
- def count_matches(regex)
- lines.select{|l| l.match(regex)}.size
- end
-
def handle_destroy_with_match
+ match_regex = new_match_regex
match_count = count_matches(match_regex)
if match_count > 1 && resource[:multiple].to_s != 'true'
raise Puppet::Error, "More than one line in file '#{resource[:path]}' matches pattern '#{resource[:match]}'"
@@ -116,27 +128,23 @@ Puppet::Type.type(:file_line).provide(:ruby) do
local_lines = lines
File.open(resource[:path],'w') do |fh|
- fh.write(local_lines.reject{|l| match_regex.match(l) }.join(''))
+ fh.write(local_lines.reject{ |line| match_regex.match(line) }.join(''))
end
end
def handle_destroy_line
local_lines = lines
File.open(resource[:path],'w') do |fh|
- fh.write(local_lines.reject{|l| l.chomp == resource[:line] }.join(''))
+ fh.write(local_lines.reject{ |line| line.chomp == resource[:line] }.join(''))
end
end
- ##
- # append the line to the file.
- #
- # @api private
- def append_line
- File.open(resource[:path], 'w') do |fh|
- lines.each do |l|
- fh.puts(l)
+ def handle_append_line
+ File.open(resource[:path],'w') do |fh|
+ lines.each do |line|
+ fh.puts(line)
end
- fh.puts resource[:line]
+ fh.puts(resource[:line])
end
end
end
diff --git a/lib/puppet/type/file_line.rb b/lib/puppet/type/file_line.rb
index 3d691bf..b2357b8 100644
--- a/lib/puppet/type/file_line.rb
+++ b/lib/puppet/type/file_line.rb
@@ -58,7 +58,7 @@ Puppet::Type.newtype(:file_line) do
encoding => "iso-8859-1",
}
- Files with special characters that are not valid UTF-8 will give the
+ Files with special characters that are not valid UTF-8 will give the
error message "invalid byte sequence in UTF-8". In this case, determine
the correct file encoding and specify the correct encoding using the
encoding attribute, the value of which needs to be a valid Ruby character
@@ -136,6 +136,12 @@ Puppet::Type.newtype(:file_line) do
defaultto 'UTF-8'
end
+ newparam(:append_on_no_match) do
+ desc 'If true, append line if match is not found. If false, do not append line if a match is not found'
+ newvalues(true, false)
+ defaultto true
+ end
+
# Autorequire the file resource if it's being managed
autorequire(:file) do
self[:path]