Puppet Function: easy_type::yaml_with_include

Defined in:
lib/puppet/functions/easy_type/yaml_with_include.rb
Function type:
Ruby 4.x API

Overview

easy_type::yaml_with_include(Hash $options, Any $context)Any

Parameters:

  • options (Hash)
  • context (Any)

Returns:

  • (Any)


23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/puppet/functions/easy_type/yaml_with_include.rb', line 23

Puppet::Functions.create_function('easy_type::yaml_with_include') do

  dispatch :yaml_with_include do
    param 'Hash', :options
    param 'Any', :context
  end
  
  argument_mismatch :missing_path do
    param 'Hash', :options
    param 'Puppet::LookupContext', :context
  end

  #
  # Process a yaml file that might contain include statements
  #
  def yaml_with_include(options, context)
    path = options['path']
    include_path = [File.dirname(path)] # Put first include path on the stack
    context.cached_file_data(path) do |content|
      while contains_include?(content) do
        replace_include_with_content(path, content, include_path, context)
      end
      begin
        data = Puppet::Util::Yaml.safe_load(content, [Symbol], path)
        if data.is_a?(Hash)
          Puppet::Pops::Lookup::HieraConfig.symkeys_to_string(data)
        else
          msg = _("%{path}: file does not contain a valid yaml hash" % { path: path })
          raise Puppet::DataBinding::LookupError, msg if Puppet[:strict] == :error && data != false
          Puppet.warning(msg)
          {}
        end
      rescue Puppet::Util::Yaml::YamlLoadError => ex
        # YamlLoadErrors include the absolute path to the file, so no need to add that
        raise Puppet::DataBinding::LookupError, _("Unable to parse %{message}") % { message: ex.message }
      end
    end
  end

  #
  # Regular expression that identifies a include statement
  # 
  def include_regexp
    /^#\s?@include\s?'(\S+)'.*$/.freeze
  end

  def replace_include_regexp(file)
    /^#\s?@include\s+'#{file}'.*$/
  end

  #
  # Return true if the content contains any include statements
  #
  def contains_include?(content)
    content =~ include_regexp
  end

  #
  # Return an array of the files that are included in the content
  #
  def included_files(content)
    content.scan(include_regexp).flatten
  end

  #
  # Replace the content that contains any include statements, witht the
  # include statment replaced with the actual include content
  #
  def replace_include_with_content(path, content, include_path, context)
    included_files(content).each do | file|
      interpolated_file = context.interpolate(file)
      context.explain { "Interpolated file '#{file}' to '#{interpolated_file}'"} if file != interpolated_file
      include_file = File.expand_path("#{include_path.last}/#{file}")
      context.explain { "Including file '#{include_file}' into contents of '#{path}'" } 
      content.gsub!(replace_include_regexp(file), include_contents(file, include_path.last, context) )
      include_path << File.dirname(include_file)
    end
  end

  #
  # Return the content of the specified include file
  #
  def include_contents(include_file, include_path, context)
    full_path = "#{include_path}/#{include_file}"
    if File.exist?(full_path) && File.file?(full_path)
      data = context.cached_file_data(full_path)
      data.gsub!(/^---$/m,'')      # Remove start of yaml and any data before if it is specified
      data.gsub!(/^\.\.\.$/m,'')    # Remove end of yaml and all data afte it if it is specified
      data
    else
      context.explain { "Included file '#{include_path}/#{include_file}' not found or not a file." }
      ''  # Replace the include with empty content so the hiera processing can continue
    end
  end

  def missing_path(options, context)
    "one of 'path', 'paths' 'glob', 'globs' or 'mapped_paths' must be declared in hiera.yaml when using this data_hash function"
  end
end