| 
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142 | # File 'lib/puppet/parser/functions/foreman.rb', line 49
newfunction(:foreman, :type => :rvalue) do |args|
    raise Puppet::ParseError, "Foreman: Must supply a Hash to foreman(), not a #{args[0].class}" unless args[0].is_a? Hash
  args_hash     = args[0]
  item          = args_hash["item"]
  search        = args_hash["search"]
  per_page      = args_hash["per_page"]     || "20"
  use_tfmproxy  = args_hash["use_tfmproxy"] || false
  foreman_url   = args_hash["foreman_url"]  || "https://localhost"   foreman_user  = args_hash["foreman_user"] || "admin"               foreman_pass  = args_hash["foreman_pass"] || "changeme"            filter_result = args_hash['filter_result'] || false
  timeout       = (args_hash['timeout']      || 5).to_i
    searchable_items = %w{ environments fact_values hosts hostgroups puppetclasses smart_proxies subnets }
  raise Puppet::ParseError, "Foreman: Invalid item to search on: #{item}, must be one of #{searchable_items.join(", ")}." unless searchable_items.include?(item)
  raise Puppet::ParseError, "Foreman: Invalid filter_result: #{filter_result}, must be a String or an Array" unless filter_result.is_a? String or filter_result.is_a? Array or filter_result.is_a? Hash or filter_result == false
  begin
    path = "/api/#{CGI.escape(item)}?search=#{CGI.escape(search)}&per_page=#{CGI.escape(per_page)}"
    req = Net::HTTP::Get.new(path)
    req['Content-Type'] = 'application/json'
    req['Accept'] = 'application/json'
    if use_tfmproxy
      configfile = '/etc/foreman-proxy/settings.yml'
      configfile = use_tfmproxy if use_tfmproxy.is_a? String
      raise Puppet::ParseError, "File #{configfile} not found while use_tfmproxy is enabled" unless File.exists?(configfile)
      tfmproxy = YAML.load(File.read(configfile))
      uri = URI.parse(tfmproxy[:foreman_url])
      http = Net::HTTP.new(uri.host, uri.port)
      http.use_ssl = true
      http.ca_file = tfmproxy[:foreman_ssl_ca]
      http.cert = OpenSSL::X509::Certificate.new(File.read(tfmproxy[:foreman_ssl_cert]))
      http.key = OpenSSL::PKey::RSA.new(File.read(tfmproxy[:foreman_ssl_key]), nil)
      http.verify_mode = OpenSSL::SSL::VERIFY_PEER
    else
      uri = URI.parse(foreman_url)
      http = Net::HTTP.new(uri.host, uri.port)
      req.basic_auth(foreman_user, foreman_pass)
      http.use_ssl = true if uri.scheme == 'https'
      http.verify_mode = OpenSSL::SSL::VERIFY_NONE if http.use_ssl?
    end
    results = Timeout::timeout(timeout) { PSON.parse http.request(req).body }
  rescue Exception => e
    raise Puppet::ParseError, "Failed to contact Foreman at #{foreman_url}: #{e}"
  end
    if filter_result != false and results.has_key?('results')
    filtered_results = Array.new
    if filter_result.is_a? String
            results['results'].each do |result|
        if result.has_key?(filter_result)
          filtered_results << result[filter_result]
        end
      end
    elsif filter_result.is_a? Array
            results['results'].each do |result|
        resulthash = Hash.new
        result.each do |key,value|
          if filter_result.include? key
            resulthash[key] = result[key]
          end
        end
        if resulthash != {}
          filtered_results << resulthash
        end
      end
    else
            results['results'].each do |result|
        resulthash = Hash.new
        result.each do |key,value|
          if filter_result.include? key
            resulthash[filter_result[key]] = result[key]
          end
        end
        if resulthash != {}
          filtered_results << resulthash
        end
      end
    end
   return filtered_results
  end
    return results
end |