From 740ca7dc8053be93e43392ca61b2f308c0596d19 Mon Sep 17 00:00:00 2001
From: Reid Vandewiele <reid@puppetlabs.com>
Date: Fri, 7 Apr 2017 15:13:59 -0700
Subject: (FACT-932) Add new function, fact()

The fact() function allows dot-notation reference to facts. It is an
alternative to using $facts directly with array-indexing. Array-indexing
is often onerous to use since it doesn't align with how structured facts
are accessed elsewhere in the ecosystem and if any element in a
multi-step path doesn't exist, array indexing can cause a compilation
failure.

Example usage:

    fact('os.family')
---
 lib/puppet/functions/fact.rb | 58 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)
 create mode 100644 lib/puppet/functions/fact.rb

(limited to 'lib')

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
-- 
cgit v1.2.3