Class: Puppet::Provider::ElasticREST
- Inherits:
-
Puppet::Provider
- Object
- Puppet::Provider
- Puppet::Provider::ElasticREST
- Defined in:
- lib/puppet/provider/elastic_rest.rb
Overview
Parent class encapsulating general-use functions for children REST-based providers.
Class Attribute Summary collapse
-
.api_discovery_uri ⇒ Object
Returns the value of attribute api_discovery_uri.
-
.api_resource_style ⇒ Object
Returns the value of attribute api_resource_style.
-
.api_uri ⇒ Object
Returns the value of attribute api_uri.
-
.discrete_resource_creation ⇒ Object
Returns the value of attribute discrete_resource_creation.
-
.metadata ⇒ Object
Returns the value of attribute metadata.
-
.metadata_pipeline ⇒ Object
Returns the value of attribute metadata_pipeline.
-
.query_string ⇒ Object
Returns the value of attribute query_string.
Class Method Summary collapse
-
.api_objects(protocol = 'http', host = 'localhost', port = 9200, timeout = 10, username = nil, password = nil, ca_file = nil, ca_path = nil, validate_tls = true) ⇒ Object
Fetch Elasticsearch API objects.
-
.format_uri(resource_path, property_flush = {}) ⇒ Object
Helper to format a remote URL request for Elasticsearch which takes into account path ordering, et cetera.
-
.instances ⇒ Object
Fetch an array of provider objects from the Elasticsearch API.
-
.prefetch(resources) ⇒ Object
Unlike a typical #prefetch, which just ties discovered #instances to the correct resources, we need to quantify all the ways the resources in the catalog know about Elasticsearch API access and use those settings to fetch any templates we can before associating resources and providers.
-
.process_body(body) ⇒ Object
Process the JSON response body.
-
.process_metadata(raw_metadata) ⇒ Object
Passes API objects through arbitrary Procs/lambdas in order to postprocess API responses.
-
.rest(http, req, timeout = 10, username = nil, password = nil, validate_tls: true) ⇒ Object
Perform a REST API request against the indicated endpoint.
Instance Method Summary collapse
-
#create ⇒ Object
Set this provider’s ‘:ensure` property to `:present`.
-
#destroy ⇒ Object
Set this provider’s ‘:ensure` property to `:absent`.
- #exists? ⇒ Boolean
-
#flush ⇒ Object
Call Elasticsearch’s REST API to appropriately PUT/DELETE/or otherwise update any managed API objects.
-
#generate_body ⇒ Object
Generate a request body.
-
#initialize(value = {}) ⇒ ElasticREST
constructor
A new instance of ElasticREST.
-
#metadata ⇒ Object
Fetch arbitrary metadata for the class from an instance object.
-
#query_string ⇒ Object
Retrieve the class query_string variable.
Constructor Details
#initialize(value = {}) ⇒ ElasticREST
Returns a new instance of ElasticREST.
177 178 179 180 |
# File 'lib/puppet/provider/elastic_rest.rb', line 177 def initialize(value = {}) super(value) @property_flush = {} end |
Class Attribute Details
.api_discovery_uri ⇒ Object
Returns the value of attribute api_discovery_uri.
11 12 13 |
# File 'lib/puppet/provider/elastic_rest.rb', line 11 def api_discovery_uri @api_discovery_uri end |
.api_resource_style ⇒ Object
Returns the value of attribute api_resource_style.
11 12 13 |
# File 'lib/puppet/provider/elastic_rest.rb', line 11 def api_resource_style @api_resource_style end |
.api_uri ⇒ Object
Returns the value of attribute api_uri.
11 12 13 |
# File 'lib/puppet/provider/elastic_rest.rb', line 11 def api_uri @api_uri end |
.discrete_resource_creation ⇒ Object
Returns the value of attribute discrete_resource_creation.
11 12 13 |
# File 'lib/puppet/provider/elastic_rest.rb', line 11 def discrete_resource_creation @discrete_resource_creation end |
.metadata ⇒ Object
Returns the value of attribute metadata.
11 12 13 |
# File 'lib/puppet/provider/elastic_rest.rb', line 11 def @metadata end |
.metadata_pipeline ⇒ Object
Returns the value of attribute metadata_pipeline.
11 12 13 |
# File 'lib/puppet/provider/elastic_rest.rb', line 11 def @metadata_pipeline end |
.query_string ⇒ Object
Returns the value of attribute query_string.
11 12 13 |
# File 'lib/puppet/provider/elastic_rest.rb', line 11 def query_string @query_string end |
Class Method Details
.api_objects(protocol = 'http', host = 'localhost', port = 9200, timeout = 10, username = nil, password = nil, ca_file = nil, ca_path = nil, validate_tls = true) ⇒ Object
Fetch Elasticsearch API objects. Accepts a variety of argument functions dictating how to connect to the Elasticsearch API.
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 |
# File 'lib/puppet/provider/elastic_rest.rb', line 87 def self.api_objects(protocol = 'http', host = 'localhost', port = 9200, timeout = 10, username = nil, password = nil, ca_file = nil, ca_path = nil, validate_tls = true) uri = URI("#{protocol}://#{host}:#{port}/#{format_uri(api_discovery_uri)}") http = Net::HTTP.new uri.host, uri.port req = Net::HTTP::Get.new uri.request_uri http.use_ssl = uri.scheme == 'https' [[ca_file, :ca_file=], [ca_path, :ca_path=]].each do |arg, method| http.send method, arg if arg && http.respond_to?(method) end response = rest http, req, timeout, username, password, validate_tls: validate_tls results = [] results = process_body(response.body) if response.respond_to?(:code) && response.code.to_i == 200 results end |
.format_uri(resource_path, property_flush = {}) ⇒ Object
Helper to format a remote URL request for Elasticsearch which takes into account path ordering, et cetera.
66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/puppet/provider/elastic_rest.rb', line 66 def self.format_uri(resource_path, property_flush = {}) return api_uri if resource_path.nil? || api_resource_style == :bare if discrete_resource_creation && !property_flush[:ensure].nil? resource_path else case api_resource_style when :prefix "#{resource_path}/#{api_uri}" else "#{api_uri}/#{resource_path}" end end end |
.instances ⇒ Object
Fetch an array of provider objects from the Elasticsearch API.
140 141 142 |
# File 'lib/puppet/provider/elastic_rest.rb', line 140 def self.instances api_objects.map { |resource| new resource } end |
.prefetch(resources) ⇒ Object
Unlike a typical #prefetch, which just ties discovered #instances to the correct resources, we need to quantify all the ways the resources in the catalog know about Elasticsearch API access and use those settings to fetch any templates we can before associating resources and providers.
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/puppet/provider/elastic_rest.rb', line 148 def self.prefetch(resources) # Get all relevant API access methods from the resources we know about res = resources.map do |_, resource| p = resource.parameters [ p[:protocol].value, p[:host].value, p[:port].value, p[:timeout].value, (p.key?(:username) ? p[:username].value : nil), (p.key?(:password) ? p[:password].value : nil), (p.key?(:ca_file) ? p[:ca_file].value : nil), (p.key?(:ca_path) ? p[:ca_path].value : nil), (p.key?(:validate_tls) ? p[:validate_tls].value : true), ] # Deduplicate identical settings, and fetch templates end.uniq res = res.map do |api| api_objects(*api) # Flatten and deduplicate the array, instantiate providers, and do the # typical association dance end res.flatten.uniq.map { |resource| new resource }.each do |prov| if (resource = resources[prov.name]) resource.provider = prov end end end |
.process_body(body) ⇒ Object
Process the JSON response body
116 117 118 119 120 121 122 123 124 125 |
# File 'lib/puppet/provider/elastic_rest.rb', line 116 def self.process_body(body) JSON.parse(body).map do |object_name, api_object| { :name => object_name, :ensure => :present, => (api_object), :provider => name } end end |
.process_metadata(raw_metadata) ⇒ Object
Passes API objects through arbitrary Procs/lambdas in order to postprocess API responses.
129 130 131 132 133 134 135 136 137 |
# File 'lib/puppet/provider/elastic_rest.rb', line 129 def self.() if .is_a?(Array) && !.empty? .reduce() do |md, processor| processor.call md end else end end |
.rest(http, req, timeout = 10, username = nil, password = nil, validate_tls: true) ⇒ Object
Perform a REST API request against the indicated endpoint.
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 |
# File 'lib/puppet/provider/elastic_rest.rb', line 31 def self.rest(http, req, timeout = 10, username = nil, password = nil, validate_tls: true) if username && password req.basic_auth username, password elsif username || password Puppet.warning( 'username and password must both be defined, skipping basic auth' ) end req['Accept'] = 'application/json' http.read_timeout = timeout http.open_timeout = timeout http.verify_mode = OpenSSL::SSL::VERIFY_NONE unless validate_tls begin http.request req rescue EOFError => e # Because the provider attempts a best guess at API access, we # only fail when HTTP operations fail for mutating methods. unless %w[GET OPTIONS HEAD].include? req.method raise Puppet::Error, "Received '#{e}' from the Elasticsearch API. Are your API settings correct?" end end end |
Instance Method Details
#create ⇒ Object
Set this provider’s ‘:ensure` property to `:present`.
274 275 276 |
# File 'lib/puppet/provider/elastic_rest.rb', line 274 def create @property_flush[:ensure] = :present end |
#destroy ⇒ Object
Set this provider’s ‘:ensure` property to `:absent`.
283 284 285 |
# File 'lib/puppet/provider/elastic_rest.rb', line 283 def destroy @property_flush[:ensure] = :absent end |
#exists? ⇒ Boolean
278 279 280 |
# File 'lib/puppet/provider/elastic_rest.rb', line 278 def exists? @property_hash[:ensure] == :present end |
#flush ⇒ Object
Call Elasticsearch’s REST API to appropriately PUT/DELETE/or otherwise update any managed API objects.
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 |
# File 'lib/puppet/provider/elastic_rest.rb', line 195 def flush Puppet.debug('Got to flush') uri = URI( format( '%s://%s:%d/%s', resource[:protocol], resource[:host], resource[:port], self.class.format_uri(resource[:name], @property_flush) ) ) uri.query = URI.encode_www_form query_string if query_string Puppet.debug("Generated URI = #{uri.inspect}") case @property_flush[:ensure] when :absent req = Net::HTTP::Delete.new uri.request_uri else req = Net::HTTP::Put.new uri.request_uri req.body = generate_body Puppet.debug("Generated body looks like: #{req.body.inspect}") # As of Elasticsearch 6.x, required when requesting with a payload (so we # set it always to be safe) req['Content-Type'] = 'application/json' if req['Content-Type'].nil? end http = Net::HTTP.new uri.host, uri.port http.use_ssl = uri.scheme == 'https' %i[ca_file ca_path].each do |arg| http.send "#{arg}=".to_sym, resource[arg] if !resource[arg].nil? && http.respond_to?(arg) end response = self.class.rest( http, req, resource[:timeout], resource[:username], resource[:password], validate_tls: resource[:validate_tls] ) # Attempt to return useful error output unless response.code.to_i == 200 Puppet.debug("Non-OK reponse: Body = #{response.body.inspect}") json = JSON.parse(response.body) err_msg = if json.key? 'error' if json['error'].is_a?(Hash) \ && json['error'].key?('root_cause') # Newer versions have useful output json['error']['root_cause'].first['reason'] else # Otherwise fallback to old-style error messages json['error'] end else # As a last resort, return the response error code "HTTP #{response.code}" end raise Puppet::Error, "Elasticsearch API responded with: #{err_msg}" end @property_hash = self.class.api_objects( resource[:protocol], resource[:host], resource[:port], resource[:timeout], resource[:username], resource[:password], resource[:ca_file], resource[:ca_path], resource[:validate_tls].nil? ? true : resource[:validate_tls] ).find do |t| t[:name] == resource[:name] end end |
#generate_body ⇒ Object
Generate a request body
183 184 185 186 187 188 189 190 191 |
# File 'lib/puppet/provider/elastic_rest.rb', line 183 def generate_body JSON.generate( if != :content && @property_flush[:ensure] == :present { .to_s => resource[] } else resource[] end ) end |
#metadata ⇒ Object
Fetch arbitrary metadata for the class from an instance object.
17 18 19 |
# File 'lib/puppet/provider/elastic_rest.rb', line 17 def self.class. end |
#query_string ⇒ Object
Retrieve the class query_string variable
24 25 26 |
# File 'lib/puppet/provider/elastic_rest.rb', line 24 def query_string self.class.query_string end |