class Inspec::Resources::Elasticsearch

def curl_command_string(username, password, ssl_verify)

def curl_command_string(username, password, ssl_verify)
  cmd_string = ['curl']
  cmd_string << '-k' unless ssl_verify
  cmd_string << "-H 'Content-Type: application/json'"
  cmd_string << " -u #{username}:#{password}" unless username.nil? || password.nil?
  cmd_string << URI.join(url, '_nodes')
  cmd_string.join(' ')
end

def fix_mash_key_collision(data)


Any key that is in conflict will be renamed "es_ORIGINALKEY"

hard-coding a bunch of key renames.
method on a Hashie::Mash instance. This is a crude way of avoiding those warnings without
Hashie::Mash will throw warnings if the Mash contains a key that is the same as a built-in
def fix_mash_key_collision(data)
  test_mash = Hashie::Mash.new
  new_data = {}
  data.each do |key, value|
    new_key = test_mash.respond_to?(key.to_sym) ? "es_#{key}" : key
    new_value = value.is_a?(Hash) ? fix_mash_key_collision(value) : value
    new_data[new_key] = new_value
  end
  new_data
end

def initialize(opts = {})

def initialize(opts = {})
  return skip_resource 'Package `curl` not avaiable on the host' unless inspec.command('curl').exist?
  @url = opts.fetch(:url, 'http://localhost:9200')
  username   = opts.fetch(:username, nil)
  password   = opts.fetch(:password, nil)
  ssl_verify = opts.fetch(:ssl_verify, true)
  cmd = inspec.command(curl_command_string(username, password, ssl_verify))
  # after implementation of PR #2235, this begin..rescue won't be necessary.
  # The checks in verify_curl_success! can raise their own skip message exception.
  begin
    verify_curl_success!(cmd)
  rescue => e
    return skip_resource e.message
  end
  begin
    content = JSON.parse(cmd.stdout)
    # after implementation of PR #2235, this can be broken out of the begin..rescue
    # clause. The checks in verify_json_payload! can raise their own skip message exception.
    verify_json_payload!(content)
  rescue JSON::ParserError => e
    return skip_resource "Couldn't parse the Elasticsearch response: #{e.message}"
  rescue => e
    return skip_resource e.message
  end
  @nodes = parse_cluster(content)
end

def parse_cluster(content)

def parse_cluster(content)
  return [] unless content['nodes']
  nodes = []
  content['nodes'].each do |node_id, node_data|
    node_data = fix_mash_key_collision(node_data)
    node = Hashie::Mash.new(node_data)
    node.node_id = node_id
    node.plugin_list = node.plugins.map(&:name)
    node.module_list = node.modules.map(&:name)
    node.cluster_name = node.settings.cluster.name
    nodes << node
  end
  nodes
end

def to_s

def to_s
  "Elasticsearch Cluster #{url}"
end

def verify_curl_success!(cmd)

def verify_curl_success!(cmd)
  # the following lines captures known possible curl command errors and provides compact skip resource messeges
  if cmd.stderr =~ /Failed to connect/
    raise "Connection refused - please check the URL #{url} for accuracy"
  end
  if cmd.stderr =~ /Peer's Certificate issuer is not recognized/
    raise 'Connection refused - peer certificate issuer is not recognized'
  end
  raise "Error fetching Elastcsearch data from curl #{url}: #{cmd.stderr}" unless cmd.exit_status.zero?
end

def verify_json_payload!(content)

def verify_json_payload!(content)
  unless content['error'].nil?
    raise "#{content['error']['type']}: #{content['error']['reason']}"
  end
  raise 'No successful nodes available in cluster' if content['_nodes']['successful'].zero?
end