class ChefZero::Endpoints::SearchEndpoint
/search/INDEX
Public Instance Methods
get(request)
click to toggle source
# File lib/chef_zero/endpoints/search_endpoint.rb, line 12 def get(request) orgname = request.rest_path[1] results = search(request, orgname) results["rows"] = results["rows"].map { |name, uri, value, search_value| value } json_response(200, results) rescue ChefZero::Solr::ParseError bad_search_request(request) end
post(request)
click to toggle source
# File lib/chef_zero/endpoints/search_endpoint.rb, line 23 def post(request) orgname = request.rest_path[1] full_results = search(request, orgname) keys = FFI_Yajl::Parser.parse(request.body) partial_results = full_results["rows"].map do |name, uri, doc, search_value| data = {} keys.each_pair do |key, path| if path.size > 0 value = search_value path.each do |path_part| value = value[path_part] unless value.nil? end data[key] = value else data[key] = nil end end { "url" => uri, "data" => data, } end json_response(200, { "rows" => partial_results, "start" => full_results["start"], "total" => full_results["total"], }) rescue ChefZero::Solr::ParseError bad_search_request(request) end
Private Instance Methods
bad_search_request(request)
click to toggle source
# File lib/chef_zero/endpoints/search_endpoint.rb, line 56 def bad_search_request(request) query_string = request.query_params["q"] resp = { "error" => ["invalid search query: '#{query_string}'"] } json_response(400, resp) end
deep_merge!(source, dest)
click to toggle source
Deep Merge core documentation. deep_merge! method permits merging of arbitrary child elements. The two top level elements must be hashes. These hashes can contain unlimited (to stack limit) levels of child elements. These child elements to not have to be of the same types. Where child elements are of the same type, deep_merge will attempt to merge them together. Where child elements are not of the same type, deep_merge will skip or optionally overwrite the destination element with the contents of the source element at that level. So if you have two hashes like this:
source = {:x => [1,2,3], :y => 2} dest = {:x => [4,5,'6'], :y => [7,8,9]} dest.deep_merge!(source) Results: {:x => [1,2,3,4,5,'6'], :y => 2}
By default, “deep_merge!” will overwrite any unmergeables and merge everything else. To avoid this, use “deep_merge” (no bang/exclamation mark)
# File lib/chef_zero/endpoints/search_endpoint.rb, line 172 def deep_merge!(source, dest) # if dest doesn't exist, then simply copy source to it if dest.nil? dest = source; return dest end case source when nil dest when Hash source.each do |src_key, src_value| if dest.is_a?(Hash) if dest[src_key] dest[src_key] = deep_merge!(src_value, dest[src_key]) else # dest[src_key] doesn't exist so we take whatever source has dest[src_key] = src_value end else # dest isn't a hash, so we overwrite it completely dest = source end end when Array if dest.is_a?(Array) dest |= source else dest = source end when String dest = source else # src_hash is not an array or hash, so we'll have to overwrite dest dest = source end dest end
expand_for_indexing(value, index, id)
click to toggle source
# File lib/chef_zero/endpoints/search_endpoint.rb, line 83 def expand_for_indexing(value, index, id) if index == "node" result = {} deep_merge!(value["default"] || {}, result) deep_merge!(value["normal"] || {}, result) deep_merge!(value["override"] || {}, result) deep_merge!(value["automatic"] || {}, result) result["recipe"] = [] result["role"] = [] if value["run_list"] value["run_list"].each do |run_list_entry| if run_list_entry =~ /^(recipe|role)\[(.*)\]/ result[$1] << $2 end end end value.each_pair do |key, val| result[key] = val unless %w{default normal override automatic}.include?(key) end result elsif !%w{client environment role}.include?(index) ChefData::DataNormalizer.normalize_data_bag_item(value, index, id, "GET") else value end end
search(request, orgname = nil)
click to toggle source
# File lib/chef_zero/endpoints/search_endpoint.rb, line 111 def search(request, orgname = nil) # Extract parameters index = request.rest_path[3] query_string = request.query_params["q"] || "*:*" solr_query = ChefZero::Solr::SolrParser.new(query_string).parse sort_string = request.query_params["sort"] start = request.query_params["start"].to_i rows = request.query_params["rows"].to_i # Get the search container container, expander = search_container(request, index, orgname) # Search! result = [] list_data(request, container).each do |name| value = get_data(request, container + [name]) expanded = expander.call(FFI_Yajl::Parser.parse(value), name) result << [ name, build_uri(request.base_uri, container + [name]), expanded, expand_for_indexing(expanded, index, name) ] end result = result.select do |name, uri, value, search_value| solr_query.matches_doc?(ChefZero::Solr::SolrDoc.new(search_value, name)) end total = result.size # Sort if sort_string sort_key, sort_order = sort_string.split(/\s+/, 2) result = result.sort_by { |name, uri, value, search_value| ChefZero::Solr::SolrDoc.new(search_value, name)[sort_key] } result = result.reverse if sort_order == "DESC" end { # Paginate # # Slice the array based on the value of the "rows" query parameter. If # this is a positive integer, we'll get the number of rows asked for. # If it's nil, we'll get -1, which gives us all of the elements. # # Do the same for "start", which will start at 0 if that value is not # given. "rows" => result[start..(rows - 1)], # Also return start and total in the object "start" => start, "total" => total, } end
search_container(request, index, orgname)
click to toggle source
# File lib/chef_zero/endpoints/search_endpoint.rb, line 62 def search_container(request, index, orgname) relative_parts, normalize_proc = case index when "client" [ ["clients"], Proc.new { |client, name| ChefData::DataNormalizer.normalize_client(client, name, orgname) } ] when "node" [ ["nodes"], Proc.new { |node, name| ChefData::DataNormalizer.normalize_node(node, name) } ] when "environment" [ ["environments"], Proc.new { |environment, name| ChefData::DataNormalizer.normalize_environment(environment, name) } ] when "role" [ ["roles"], Proc.new { |role, name| ChefData::DataNormalizer.normalize_role(role, name) } ] else [ ["data", index], Proc.new { |data_bag_item, id| ChefData::DataNormalizer.normalize_data_bag_item(data_bag_item, index, id, "DELETE") } ] end [ request.rest_path[0..1] + relative_parts, normalize_proc, ] end