diff options
author | jkeiser <jkeiser@opscode.com> | 2012-12-19 23:22:54 -0800 |
---|---|---|
committer | jkeiser <jkeiser@opscode.com> | 2012-12-19 23:23:21 -0800 |
commit | 666374b272a8851a2c57530a71a6183d4d06a648 (patch) | |
tree | b53efd8134aa36ab0d459f3e4e87e1a6bbd1fe21 /lib/chef_zero/endpoints/search_endpoint.rb | |
download | chef-zero-666374b272a8851a2c57530a71a6183d4d06a648.tar.gz |
Initial commit (moved/split up from jk/tiny-chef-server branch of jkeiser/chef)
Diffstat (limited to 'lib/chef_zero/endpoints/search_endpoint.rb')
-rw-r--r-- | lib/chef_zero/endpoints/search_endpoint.rb | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/lib/chef_zero/endpoints/search_endpoint.rb b/lib/chef_zero/endpoints/search_endpoint.rb new file mode 100644 index 0000000..8a66d9a --- /dev/null +++ b/lib/chef_zero/endpoints/search_endpoint.rb @@ -0,0 +1,139 @@ +require 'json' +require 'chef/mixin/deep_merge' +require 'chef_zero/endpoints/rest_object_endpoint' +require 'chef_zero/data_normalizer' +require 'chef_zero/rest_error_response' +require 'chef_zero/solr/solr_parser' +require 'chef_zero/solr/solr_doc' + +module ChefZero + module Endpoints + # /search/INDEX + class SearchEndpoint < RestBase + def get(request) + results = search(request) + results['rows'] = results['rows'].map { |name,uri,value,search_value| value } + json_response(200, results) + end + + def post(request) + full_results = search(request) + keys = JSON.parse(request.body, :create_additions => false) + 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] if !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'] + }) + end + + private + + def search_container(request, index) + case index + when 'client' + [ data['clients'], Proc.new { |client, name| DataNormalizer.normalize_client(client, name) }, build_uri(request.base_uri, [ 'clients' ]) ] + when 'node' + [ data['nodes'], Proc.new { |node, name| DataNormalizer.normalize_node(node, name) }, build_uri(request.base_uri, [ 'nodes' ]) ] + when 'environment' + [ data['environments'], Proc.new { |environment, name| DataNormalizer.normalize_environment(environment, name) }, build_uri(request.base_uri, [ 'environments' ]) ] + when 'role' + [ data['roles'], Proc.new { |role, name| DataNormalizer.normalize_role(role, name) }, build_uri(request.base_uri, [ 'roles' ]) ] + else + [ data['data'][index], Proc.new { |data_bag_item, id| DataNormalizer.normalize_data_bag_item(data_bag_item, index, id, 'DELETE') }, build_uri(request.base_uri, [ 'data', index ]) ] + end + end + + def expand_for_indexing(value, index, id) + if index == 'node' + result = {} + Chef::Mixin::DeepMerge.deep_merge!(value['default'] || {}, result) + Chef::Mixin::DeepMerge.deep_merge!(value['normal'] || {}, result) + Chef::Mixin::DeepMerge.deep_merge!(value['override'] || {}, result) + Chef::Mixin::DeepMerge.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, value| + result[key] = value unless %w(default normal override automatic).include?(key) + end + result + + elsif !%w(client environment role).include?(index) + DataNormalizer.normalize_data_bag_item(value, index, id, 'GET') + else + value + end + end + + def search(request) + # Extract parameters + index = request.rest_path[1] + 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'] + start = start.to_i if start + rows = request.query_params['rows'] + rows = rows.to_i if rows + + # Get the search container + container, expander, base_uri = search_container(request, index) + if container.nil? + raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, request.rest_path)}") + end + + # Search! + result = [] + container.each_pair do |name,value| + expanded = expander.call(JSON.parse(value, :create_additions => false), name) + result << [ name, build_uri(base_uri, [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 + if start + result = result[start..start+(rows||-1)] + end + { + 'rows' => result, + 'start' => start || 0, + 'total' => total + } + end + end + end +end |