module Chef::EncryptedAttribute::SearchHelper

Search Helpers to do normal or partial searches.

Public Instance Methods

assert_normal_search_response(resp) click to toggle source

Assert that the normal (no partial) search response is correct.

@param resp [Array] normal search result. @return void @raise [SearchFatalError] if the Chef search response is wrong. @api private

# File lib/chef/encrypted_attribute/search_helper.rb, line 190
def assert_normal_search_response(resp)
  return if resp.is_a?(Array)
  fail SearchFatalError,
       "Wrong response received from Normal Search: #{resp.inspect}"
end
assert_partial_search_response(resp) click to toggle source

Assert that the partial search response is correct.

@param resp [Hash] partial search result. For example:

`{ 'rows' => [ 'data' => { 'ipaddress' => '192.168.1.1' } }] }`.

@return void @raise [SearchFatalError] if the Chef search response is wrong. @api private

# File lib/chef/encrypted_attribute/search_helper.rb, line 288
def assert_partial_search_response(resp)
  return if resp.is_a?(Hash) && resp.key?('rows') &&
            resp['rows'].is_a?(Array)
  fail SearchFatalError,
       "Wrong response received from Partial Search: #{resp.inspect}"
end
assert_search_keys(keys) click to toggle source

Assert that the search keys structure format is correct.

@return void @raise [InvalidSearchKeys] if search keys structure is wrong. @api private

# File lib/chef/encrypted_attribute/search_helper.rb, line 108
def assert_search_keys(keys)
  return if valid_search_keys?(keys)
  fail InvalidSearchKeys, "Invalid search keys: #{keys.inspect}"
end
catch_search_exceptions(&block) click to toggle source

Translates Chef HTTP exceptions to search exceptions.

@yield [] the block doing the Chef Search. @return [Mixed] the value returned by the block. @api private

# File lib/chef/encrypted_attribute/search_helper.rb, line 128
def catch_search_exceptions(&block)
  block.call
rescue Net::HTTPServerException => e
  unless e.response.is_a?(Net::HTTPResponse) && e.response.code == '404'
    raise SearchFailure, "Search exception #{e.class}: #{e}"
  end
  return []
rescue Net::HTTPFatalError => e
  raise SearchFailure, "Search exception #{e.class}: #{e}"
end
empty_search?(query) click to toggle source

Check if search query is empty.

@param query [Array<String>, String] search query. @return [Boolean] `true` if search query is empty. @api private

# File lib/chef/encrypted_attribute/search_helper.rb, line 118
def empty_search?(query)
  query.is_a?(String) && query.empty? ||
    query.is_a?(Array) && query.count == 0
end
escape(str) click to toggle source

Escapes a search query string to be used in URLs.

@param str [String] query to escape. @return [String] escaped query string. @api private

# File lib/chef/encrypted_attribute/search_helper.rb, line 43
def escape(str)
  URI.escape(str.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
end
escape_query(query) click to toggle source

Escapes a search query array.

When multiple queries are provided, the result will be OR-ed.

@param query [Array<String>, String] search query. @return [String] escaped query string.

# File lib/chef/encrypted_attribute/search_helper.rb, line 53
def escape_query(query)
  query_s =
    if query.is_a?(Array)
      query.map { |item| "( #{item} )" }.compact.join(' OR ')
    else
      query.to_s
    end
  escape(query_s)
end
filter_normal_search_response(resp, name) click to toggle source

Filters normal search results that do not correspond to the searched node.

Used when searching by node name.

@param resp [Array] normal search result. @param name [String, nil] searched node name. @return [Array] The search result removing the filtered results. @raise [SearchFatalError] if more than one result is returned when

searching by node name.

@api private

# File lib/chef/encrypted_attribute/search_helper.rb, line 224
def filter_normal_search_response(resp, name)
  return resp if name.nil?
  resp.select { |row| row.name == name }.tap do |r|
    fail SearchFatalError,
         'Multiple responses received from Partial Search:'\
         " #{r.inspect}" if r.count > 1
  end
end
filter_partial_search_response(resp, name) click to toggle source

Filters partial search results that do not correspond to the searched node.

Used when searching by node name.

@param resp [Hash] partial search result. For example:

`{ 'rows' => [ 'data' => { 'ipaddress' => '192.168.1.1' } }] }`.

@param name [String, nil] searched node name. @return [Hash] The search result removing the filtered results. @raise [SearchFatalError] if more than one result is returned when

searching by node name.

@api private

# File lib/chef/encrypted_attribute/search_helper.rb, line 322
def filter_partial_search_response(resp, name)
  return resp if name.nil?
  filtered_resp = resp.select do |row|
    row['data']['name'] == name
  end
  filtered_resp.tap do |r|
    fail SearchFatalError,
         'Multiple responses received from Partial Search:'\
         " #{r.inspect}" if r.count > 1
  end
end
generate_partial_search_keys(keys) click to toggle source

Adds the `name` key to the search keys structure.

Used to get the node name when searching nodes by name.

@param keys [Hash] search keys structure. For example:

`{ipaddress: %w(ipaddress), mysql_version: %w(mysql version) }`.

@return [Hash] the search keys structure including the `name` key. For

example:
`{ipaddress: %w(ipaddress), mysql_version: %w(mysql version),
  name: %w(name) }`.

@api private

# File lib/chef/encrypted_attribute/search_helper.rb, line 306
def generate_partial_search_keys(keys)
  keys.merge('name' => %w(name))
end
parse_normal_search_response(resp, keys, name) click to toggle source

Parses a normal (no partial) full search search response.

@param resp [Array] normal search result. @param keys [Hash] search keys structure. For example:

`{ipaddress: %w(ipaddress), mysql_version: %w(mysql version) }`.

@param name [String, nil] searched node name. @return [Array<Hash>] An array with the response, for example:

`[{ 'ipaddress' => '192.168.1.1' }]`

@raise [SearchFatalError] if more than one result is returned when

searching by node name.

@api private

# File lib/chef/encrypted_attribute/search_helper.rb, line 244
def parse_normal_search_response(resp, keys, name)
  filter_normal_search_response(resp, name).map do |row|
    Hash[keys.map do |key_name, attr_ary|
      value = parse_normal_search_row_attribute(row, attr_ary)
      [key_name, value]
    end]
  end
end
parse_normal_search_row_attribute(row, attr_ary) click to toggle source

Parses a normal (no partial) search response row.

@param row [Array] the normal search result row. @param attr_ary [Array<String>] key path as Array. @return [Hash] A hash with the response row, for example:

`[ 'ipaddress' => '192.168.1.1' }`

@api private

# File lib/chef/encrypted_attribute/search_helper.rb, line 203
def parse_normal_search_row_attribute(row, attr_ary)
  attr_ary.reduce(row) do |r, attr|
    if r.respond_to?(attr)
      r.send(attr)
    elsif r.respond_to?(:key?)
      r[attr.to_s] if r.key?(attr.to_s)
    end
  end
end
parse_partial_search_response(resp, name, keys) click to toggle source

Parses a partial full search search response.

@param resp [Hash] partial search result. For example:

`{ 'rows' => [ 'data' => { 'ipaddress' => '192.168.1.1' } }] }`.

@param name [String, nil] searched node name. @param keys [Hash] search keys structure. For example:

`{ipaddress: %w(ipaddress), mysql_version: %w(mysql version) }`.

@return [Array<Hash>] An array with the response, for example:

`[{ 'ipaddress' => '192.168.1.1' }]`

@raise [SearchFatalError] if the Chef search response is wrong. @api private

# File lib/chef/encrypted_attribute/search_helper.rb, line 345
def parse_partial_search_response(resp, name, keys)
  filter_partial_search_response(resp['rows'], name).map do |row|
    if row.is_a?(Hash) && row['data'].is_a?(Hash)
      row['data'].tap { |r| r.delete('name') unless keys.key?('name') }
    else
      fail SearchFatalError,
           "Wrong row format received from Partial Search: #{row.inspect}"
    end
  end.compact
end
query() click to toggle source

Gets a Chef Search Query object.

@return [Chef::Search::Query] search query object instance. @api private

# File lib/chef/encrypted_attribute/search_helper.rb, line 34
def query
  Chef::Search::Query.new
end
search_by_name(type, name, keys, rows = 1000, partial_search = true) click to toggle source

Does a search in the Chef Server by node or client name.

@param type [Symbol] search index to use. See [Chef Search Indexes]

(http://docs.chef.io/chef_search.html#search-indexes).

@param name [String] node name to search. @param keys [Hash] search keys structure. For example:

`{ipaddress: %w(ipaddress), mysql_version: %w(mysql version) }`.

@param rows [Fixnum, String] maximum number of rows to return. @param partial_search [Boolean] whether to use partial search. @return [Array<Hash>] An array with the response, for example:

`[{ 'ipaddress' => '192.168.1.1' }]`

@raise [SearchFailure] if there is a Chef search error. @raise [SearchFatalError] if the Chef search response is wrong. @raise [InvalidSearchKeys] if search keys structure is wrong.

# File lib/chef/encrypted_attribute/search_helper.rb, line 177
def search_by_name(type, name, keys, rows = 1000, partial_search = true)
  search_method = partial_search ? :partial_search : :normal_search
  catch_search_exceptions do
    send(search_method, type, name, "name:#{name}", keys, rows)
  end
end
valid_search_keys?(keys) click to toggle source

Checks if a search keys structure format is correct.

This is an example of a correct search structure:

“`ruby {

ipaddress: %w(ipaddress),
mysql_version: %w(mysql version)

} “`

@param keys [Hash] search keys structure. @return [Boolean] `true` if search keys structure format is correct. @api private

# File lib/chef/encrypted_attribute/search_helper.rb, line 96
def valid_search_keys?(keys)
  return false unless keys.is_a?(Hash)
  keys.reduce(true) do |r, (k, v)|
    r && valid_search_keys_key?(k) && valid_search_keys_value?(v)
  end
end
valid_search_keys_key?(k) click to toggle source

Checks if a Hash key from a search keys structure format is correct.

@param k [Mixed] hash key to check. @return [Boolean] `true` if key is a `String` or a `Symbol`. @api private

# File lib/chef/encrypted_attribute/search_helper.rb, line 68
def valid_search_keys_key?(k)
  k.is_a?(String) || k.is_a?(Symbol)
end
valid_search_keys_value?(v) click to toggle source

Checks if a Hash value from a search keys structure format is correct.

@param v [Mixed] hash value to check. @return [Boolean] `true` if value is a `Array<String>`. @api private

# File lib/chef/encrypted_attribute/search_helper.rb, line 77
def valid_search_keys_value?(v)
  return false unless v.is_a?(Array)
  v.reduce(true) { |a, e| a && e.is_a?(String) }
end