chef-zero 4.2.3 → 4.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +201 -201
  3. data/README.md +155 -150
  4. data/Rakefile +31 -31
  5. data/bin/chef-zero +100 -100
  6. data/lib/chef_zero.rb +10 -7
  7. data/lib/chef_zero/chef_data/acl_path.rb +139 -139
  8. data/lib/chef_zero/chef_data/cookbook_data.rb +240 -240
  9. data/lib/chef_zero/chef_data/data_normalizer.rb +207 -207
  10. data/lib/chef_zero/chef_data/default_creator.rb +446 -446
  11. data/lib/chef_zero/data_store/data_already_exists_error.rb +29 -29
  12. data/lib/chef_zero/data_store/data_error.rb +31 -31
  13. data/lib/chef_zero/data_store/data_not_found_error.rb +28 -28
  14. data/lib/chef_zero/data_store/default_facade.rb +149 -149
  15. data/lib/chef_zero/data_store/interface_v1.rb +67 -67
  16. data/lib/chef_zero/data_store/interface_v2.rb +18 -18
  17. data/lib/chef_zero/data_store/memory_store.rb +33 -33
  18. data/lib/chef_zero/data_store/memory_store_v2.rb +155 -155
  19. data/lib/chef_zero/data_store/raw_file_store.rb +147 -147
  20. data/lib/chef_zero/data_store/v1_to_v2_adapter.rb +142 -142
  21. data/lib/chef_zero/data_store/v2_to_v1_adapter.rb +107 -107
  22. data/lib/chef_zero/endpoints/acl_endpoint.rb +38 -38
  23. data/lib/chef_zero/endpoints/acls_endpoint.rb +29 -29
  24. data/lib/chef_zero/endpoints/actor_endpoint.rb +94 -88
  25. data/lib/chef_zero/endpoints/actors_endpoint.rb +64 -64
  26. data/lib/chef_zero/endpoints/authenticate_user_endpoint.rb +31 -31
  27. data/lib/chef_zero/endpoints/container_endpoint.rb +22 -22
  28. data/lib/chef_zero/endpoints/containers_endpoint.rb +13 -13
  29. data/lib/chef_zero/endpoints/cookbook_endpoint.rb +39 -39
  30. data/lib/chef_zero/endpoints/cookbook_version_endpoint.rb +119 -119
  31. data/lib/chef_zero/endpoints/cookbooks_base.rb +65 -65
  32. data/lib/chef_zero/endpoints/cookbooks_endpoint.rb +19 -19
  33. data/lib/chef_zero/endpoints/data_bag_endpoint.rb +45 -45
  34. data/lib/chef_zero/endpoints/data_bag_item_endpoint.rb +25 -25
  35. data/lib/chef_zero/endpoints/data_bags_endpoint.rb +23 -23
  36. data/lib/chef_zero/endpoints/environment_cookbook_endpoint.rb +24 -24
  37. data/lib/chef_zero/endpoints/environment_cookbook_versions_endpoint.rb +123 -123
  38. data/lib/chef_zero/endpoints/environment_cookbooks_endpoint.rb +22 -22
  39. data/lib/chef_zero/endpoints/environment_endpoint.rb +33 -33
  40. data/lib/chef_zero/endpoints/environment_nodes_endpoint.rb +23 -23
  41. data/lib/chef_zero/endpoints/environment_recipes_endpoint.rb +22 -22
  42. data/lib/chef_zero/endpoints/environment_role_endpoint.rb +36 -36
  43. data/lib/chef_zero/endpoints/file_store_file_endpoint.rb +22 -22
  44. data/lib/chef_zero/endpoints/group_endpoint.rb +20 -20
  45. data/lib/chef_zero/endpoints/groups_endpoint.rb +13 -13
  46. data/lib/chef_zero/endpoints/license_endpoint.rb +25 -25
  47. data/lib/chef_zero/endpoints/node_endpoint.rb +17 -17
  48. data/lib/chef_zero/endpoints/node_identifiers_endpoint.rb +22 -0
  49. data/lib/chef_zero/endpoints/not_found_endpoint.rb +11 -11
  50. data/lib/chef_zero/endpoints/organization_association_request_endpoint.rb +22 -22
  51. data/lib/chef_zero/endpoints/organization_association_requests_endpoint.rb +30 -29
  52. data/lib/chef_zero/endpoints/organization_authenticate_user_endpoint.rb +26 -26
  53. data/lib/chef_zero/endpoints/organization_endpoint.rb +46 -41
  54. data/lib/chef_zero/endpoints/organization_user_base.rb +15 -0
  55. data/lib/chef_zero/endpoints/organization_user_endpoint.rb +26 -48
  56. data/lib/chef_zero/endpoints/organization_users_endpoint.rb +43 -14
  57. data/lib/chef_zero/endpoints/organization_validator_key_endpoint.rb +20 -20
  58. data/lib/chef_zero/endpoints/organizations_endpoint.rb +62 -55
  59. data/lib/chef_zero/endpoints/policies_endpoint.rb +151 -154
  60. data/lib/chef_zero/endpoints/principal_endpoint.rb +42 -42
  61. data/lib/chef_zero/endpoints/rest_list_endpoint.rb +42 -42
  62. data/lib/chef_zero/endpoints/rest_object_endpoint.rb +63 -63
  63. data/lib/chef_zero/endpoints/role_endpoint.rb +16 -16
  64. data/lib/chef_zero/endpoints/role_environments_endpoint.rb +14 -14
  65. data/lib/chef_zero/endpoints/sandbox_endpoint.rb +27 -27
  66. data/lib/chef_zero/endpoints/sandboxes_endpoint.rb +50 -50
  67. data/lib/chef_zero/endpoints/search_endpoint.rb +194 -192
  68. data/lib/chef_zero/endpoints/searches_endpoint.rb +18 -18
  69. data/lib/chef_zero/endpoints/server_api_version_endpoint.rb +14 -0
  70. data/lib/chef_zero/endpoints/system_recovery_endpoint.rb +30 -30
  71. data/lib/chef_zero/endpoints/user_association_request_endpoint.rb +40 -40
  72. data/lib/chef_zero/endpoints/user_association_requests_count_endpoint.rb +19 -19
  73. data/lib/chef_zero/endpoints/user_association_requests_endpoint.rb +19 -19
  74. data/lib/chef_zero/endpoints/user_organizations_endpoint.rb +22 -22
  75. data/lib/chef_zero/endpoints/version_endpoint.rb +12 -12
  76. data/lib/chef_zero/log.rb +7 -7
  77. data/lib/chef_zero/rest_base.rb +242 -214
  78. data/lib/chef_zero/rest_error_response.rb +11 -11
  79. data/lib/chef_zero/rest_request.rb +69 -65
  80. data/lib/chef_zero/rest_router.rb +45 -45
  81. data/lib/chef_zero/rspec.rb +308 -308
  82. data/lib/chef_zero/server.rb +642 -637
  83. data/lib/chef_zero/socketless_server_map.rb +92 -92
  84. data/lib/chef_zero/solr/query/binary_operator.rb +52 -52
  85. data/lib/chef_zero/solr/query/phrase.rb +23 -23
  86. data/lib/chef_zero/solr/query/range_query.rb +46 -46
  87. data/lib/chef_zero/solr/query/regexpable_query.rb +29 -29
  88. data/lib/chef_zero/solr/query/subquery.rb +37 -37
  89. data/lib/chef_zero/solr/query/term.rb +45 -45
  90. data/lib/chef_zero/solr/query/unary_operator.rb +43 -43
  91. data/lib/chef_zero/solr/solr_doc.rb +53 -53
  92. data/lib/chef_zero/solr/solr_parser.rb +203 -203
  93. data/lib/chef_zero/version.rb +3 -3
  94. data/spec/run_oc_pedant.rb +63 -56
  95. data/spec/search_spec.rb +32 -32
  96. data/spec/server_spec.rb +92 -91
  97. data/spec/socketless_server_map_spec.rb +76 -76
  98. data/spec/support/oc_pedant.rb +132 -134
  99. data/spec/support/stickywicket.pem +27 -27
  100. metadata +10 -15
  101. data/spec/run_pedant.rb +0 -103
  102. data/spec/support/pedant.rb +0 -129
@@ -1,42 +1,42 @@
1
- require 'ffi_yajl'
2
- require 'chef_zero/rest_base'
3
-
4
- module ChefZero
5
- module Endpoints
6
- # Typical REST list endpoint (/roles or /data/BAG)
7
- class RestListEndpoint < RestBase
8
- def initialize(server, identity_keys = [ 'name' ])
9
- super(server)
10
- identity_keys = [ identity_keys ] if identity_keys.is_a?(String)
11
- @identity_keys = identity_keys
12
- end
13
-
14
- attr_reader :identity_keys
15
-
16
- def get(request)
17
- # Get the result
18
- result_hash = {}
19
- list_data(request).sort.each do |name|
20
- result_hash[name] = "#{build_uri(request.base_uri, request.rest_path + [name])}"
21
- end
22
- json_response(200, result_hash)
23
- end
24
-
25
- def post(request)
26
- contents = request.body
27
- key = get_key(contents)
28
- if key.nil?
29
- error(400, "Must specify #{identity_keys.map { |k| k.inspect }.join(' or ')} in JSON")
30
- else
31
- create_data(request, request.rest_path, key, contents)
32
- json_response(201, {'uri' => "#{build_uri(request.base_uri, request.rest_path + [key])}"})
33
- end
34
- end
35
-
36
- def get_key(contents)
37
- json = FFI_Yajl::Parser.parse(contents, :create_additions => false)
38
- identity_keys.map { |k| json[k] }.select { |v| v }.first
39
- end
40
- end
41
- end
42
- end
1
+ require 'ffi_yajl'
2
+ require 'chef_zero/rest_base'
3
+
4
+ module ChefZero
5
+ module Endpoints
6
+ # Typical REST list endpoint (/roles or /data/BAG)
7
+ class RestListEndpoint < RestBase
8
+ def initialize(server, identity_keys = [ 'name' ])
9
+ super(server)
10
+ identity_keys = [ identity_keys ] if identity_keys.is_a?(String)
11
+ @identity_keys = identity_keys
12
+ end
13
+
14
+ attr_reader :identity_keys
15
+
16
+ def get(request)
17
+ # Get the result
18
+ result_hash = {}
19
+ list_data(request).sort.each do |name|
20
+ result_hash[name] = "#{build_uri(request.base_uri, request.rest_path + [name])}"
21
+ end
22
+ json_response(200, result_hash)
23
+ end
24
+
25
+ def post(request)
26
+ contents = request.body
27
+ key = get_key(contents)
28
+ if key.nil?
29
+ error(400, "Must specify #{identity_keys.map { |k| k.inspect }.join(' or ')} in JSON")
30
+ else
31
+ create_data(request, request.rest_path, key, contents)
32
+ json_response(201, {'uri' => "#{build_uri(request.base_uri, request.rest_path + [key])}"})
33
+ end
34
+ end
35
+
36
+ def get_key(contents)
37
+ json = FFI_Yajl::Parser.parse(contents, :create_additions => false)
38
+ identity_keys.map { |k| json[k] }.select { |v| v }.first
39
+ end
40
+ end
41
+ end
42
+ end
@@ -1,63 +1,63 @@
1
- require 'ffi_yajl'
2
- require 'chef_zero/rest_base'
3
- require 'chef_zero/rest_error_response'
4
-
5
- module ChefZero
6
- module Endpoints
7
- # Typical REST leaf endpoint (/roles/NAME or /data/BAG/NAME)
8
- class RestObjectEndpoint < RestBase
9
- def initialize(server, identity_keys = [ 'name' ])
10
- super(server)
11
- identity_keys = [ identity_keys ] if identity_keys.is_a?(String)
12
- @identity_keys = identity_keys
13
- end
14
-
15
- attr_reader :identity_keys
16
-
17
- def get(request)
18
- already_json_response(200, populate_defaults(request, get_data(request)))
19
- end
20
-
21
- def put(request)
22
- # We grab the old body to trigger a 404 if it doesn't exist
23
- old_body = get_data(request)
24
- request_json = FFI_Yajl::Parser.parse(request.body, :create_additions => false)
25
- key = identity_keys.map { |k| request_json[k] }.select { |v| v }.first
26
- key ||= request.rest_path[-1]
27
- # If it's a rename, check for conflict and delete the old value
28
- rename = key != request.rest_path[-1]
29
- if rename
30
- begin
31
- create_data(request, request.rest_path[0..-2], key, request.body, :data_store_exceptions)
32
- rescue DataStore::DataAlreadyExistsError
33
- return error(409, "Cannot rename '#{request.rest_path[-1]}' to '#{key}': '#{key}' already exists")
34
- end
35
- delete_data(request)
36
- already_json_response(201, populate_defaults(request, request.body))
37
- else
38
- set_data(request, request.rest_path, request.body)
39
- already_json_response(200, populate_defaults(request, request.body))
40
- end
41
- end
42
-
43
- def delete(request)
44
- result = get_data(request)
45
- delete_data(request)
46
- already_json_response(200, populate_defaults(request, result))
47
- end
48
-
49
- def patch_request_body(request)
50
- existing_value = get_data(request, nil, :nil)
51
- if existing_value
52
- request_json = FFI_Yajl::Parser.parse(request.body, :create_additions => false)
53
- existing_json = FFI_Yajl::Parser.parse(existing_value, :create_additions => false)
54
- merged_json = existing_json.merge(request_json)
55
- if merged_json.size > request_json.size
56
- return FFI_Yajl::Encoder.encode(merged_json, :pretty => true)
57
- end
58
- end
59
- request.body
60
- end
61
- end
62
- end
63
- end
1
+ require 'ffi_yajl'
2
+ require 'chef_zero/rest_base'
3
+ require 'chef_zero/rest_error_response'
4
+
5
+ module ChefZero
6
+ module Endpoints
7
+ # Typical REST leaf endpoint (/roles/NAME or /data/BAG/NAME)
8
+ class RestObjectEndpoint < RestBase
9
+ def initialize(server, identity_keys = [ 'name' ])
10
+ super(server)
11
+ identity_keys = [ identity_keys ] if identity_keys.is_a?(String)
12
+ @identity_keys = identity_keys
13
+ end
14
+
15
+ attr_reader :identity_keys
16
+
17
+ def get(request)
18
+ already_json_response(200, populate_defaults(request, get_data(request)))
19
+ end
20
+
21
+ def put(request)
22
+ # We grab the old body to trigger a 404 if it doesn't exist
23
+ old_body = get_data(request)
24
+ request_json = FFI_Yajl::Parser.parse(request.body, :create_additions => false)
25
+ key = identity_keys.map { |k| request_json[k] }.select { |v| v }.first
26
+ key ||= request.rest_path[-1]
27
+ # If it's a rename, check for conflict and delete the old value
28
+ rename = key != request.rest_path[-1]
29
+ if rename
30
+ begin
31
+ create_data(request, request.rest_path[0..-2], key, request.body, :data_store_exceptions)
32
+ rescue DataStore::DataAlreadyExistsError
33
+ return error(409, "Cannot rename '#{request.rest_path[-1]}' to '#{key}': '#{key}' already exists")
34
+ end
35
+ delete_data(request)
36
+ already_json_response(201, populate_defaults(request, request.body))
37
+ else
38
+ set_data(request, request.rest_path, request.body)
39
+ already_json_response(200, populate_defaults(request, request.body))
40
+ end
41
+ end
42
+
43
+ def delete(request)
44
+ result = get_data(request)
45
+ delete_data(request)
46
+ already_json_response(200, populate_defaults(request, result))
47
+ end
48
+
49
+ def patch_request_body(request)
50
+ existing_value = get_data(request, nil, :nil)
51
+ if existing_value
52
+ request_json = FFI_Yajl::Parser.parse(request.body, :create_additions => false)
53
+ existing_json = FFI_Yajl::Parser.parse(existing_value, :create_additions => false)
54
+ merged_json = existing_json.merge(request_json)
55
+ if merged_json.size > request_json.size
56
+ return FFI_Yajl::Encoder.encode(merged_json, :pretty => true)
57
+ end
58
+ end
59
+ request.body
60
+ end
61
+ end
62
+ end
63
+ end
@@ -1,16 +1,16 @@
1
- require 'ffi_yajl'
2
- require 'chef_zero/endpoints/rest_object_endpoint'
3
- require 'chef_zero/chef_data/data_normalizer'
4
-
5
- module ChefZero
6
- module Endpoints
7
- # /roles/NAME
8
- class RoleEndpoint < RestObjectEndpoint
9
- def populate_defaults(request, response_json)
10
- role = FFI_Yajl::Parser.parse(response_json, :create_additions => false)
11
- role = ChefData::DataNormalizer.normalize_role(role, request.rest_path[3])
12
- FFI_Yajl::Encoder.encode(role, :pretty => true)
13
- end
14
- end
15
- end
16
- end
1
+ require 'ffi_yajl'
2
+ require 'chef_zero/endpoints/rest_object_endpoint'
3
+ require 'chef_zero/chef_data/data_normalizer'
4
+
5
+ module ChefZero
6
+ module Endpoints
7
+ # /roles/NAME
8
+ class RoleEndpoint < RestObjectEndpoint
9
+ def populate_defaults(request, response_json)
10
+ role = FFI_Yajl::Parser.parse(response_json, :create_additions => false)
11
+ role = ChefData::DataNormalizer.normalize_role(role, request.rest_path[3])
12
+ FFI_Yajl::Encoder.encode(role, :pretty => true)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,14 +1,14 @@
1
- require 'ffi_yajl'
2
- require 'chef_zero/rest_base'
3
-
4
- module ChefZero
5
- module Endpoints
6
- # /roles/NAME/environments
7
- class RoleEnvironmentsEndpoint < RestBase
8
- def get(request)
9
- role = FFI_Yajl::Parser.parse(get_data(request, request.rest_path[0..3]), :create_additions => false)
10
- json_response(200, [ '_default' ] + (role['env_run_lists'].keys || []))
11
- end
12
- end
13
- end
14
- end
1
+ require 'ffi_yajl'
2
+ require 'chef_zero/rest_base'
3
+
4
+ module ChefZero
5
+ module Endpoints
6
+ # /roles/NAME/environments
7
+ class RoleEnvironmentsEndpoint < RestBase
8
+ def get(request)
9
+ role = FFI_Yajl::Parser.parse(get_data(request, request.rest_path[0..3]), :create_additions => false)
10
+ json_response(200, [ '_default' ] + (role['env_run_lists'].keys || []))
11
+ end
12
+ end
13
+ end
14
+ end
@@ -1,27 +1,27 @@
1
- require 'chef_zero/rest_base'
2
- require 'chef_zero/rest_error_response'
3
- require 'ffi_yajl'
4
-
5
- module ChefZero
6
- module Endpoints
7
- # /sandboxes/ID
8
- class SandboxEndpoint < RestBase
9
- def put(request)
10
- existing_sandbox = FFI_Yajl::Parser.parse(get_data(request), :create_additions => false)
11
- existing_sandbox['checksums'].each do |checksum|
12
- if !exists_data?(request, request.rest_path[0..1] + ['file_store', 'checksums', checksum])
13
- raise RestErrorResponse.new(503, "Checksum not uploaded: #{checksum}")
14
- end
15
- end
16
- delete_data(request)
17
- json_response(200, {
18
- :guid => request.rest_path[3],
19
- :name => request.rest_path[3],
20
- :checksums => existing_sandbox['checksums'],
21
- :create_time => existing_sandbox['create_time'],
22
- :is_completed => true
23
- })
24
- end
25
- end
26
- end
27
- end
1
+ require 'chef_zero/rest_base'
2
+ require 'chef_zero/rest_error_response'
3
+ require 'ffi_yajl'
4
+
5
+ module ChefZero
6
+ module Endpoints
7
+ # /sandboxes/ID
8
+ class SandboxEndpoint < RestBase
9
+ def put(request)
10
+ existing_sandbox = FFI_Yajl::Parser.parse(get_data(request), :create_additions => false)
11
+ existing_sandbox['checksums'].each do |checksum|
12
+ if !exists_data?(request, request.rest_path[0..1] + ['file_store', 'checksums', checksum])
13
+ raise RestErrorResponse.new(503, "Checksum not uploaded: #{checksum}")
14
+ end
15
+ end
16
+ delete_data(request)
17
+ json_response(200, {
18
+ :guid => request.rest_path[3],
19
+ :name => request.rest_path[3],
20
+ :checksums => existing_sandbox['checksums'],
21
+ :create_time => existing_sandbox['create_time'],
22
+ :is_completed => true
23
+ })
24
+ end
25
+ end
26
+ end
27
+ end
@@ -1,50 +1,50 @@
1
- require 'ffi_yajl'
2
- require 'chef_zero/rest_base'
3
-
4
- module ChefZero
5
- module Endpoints
6
- # /sandboxes
7
- class SandboxesEndpoint < RestBase
8
- def initialize(server)
9
- super(server)
10
- @next_id = 1
11
- end
12
-
13
- def post(request)
14
- sandbox_checksums = []
15
-
16
- needed_checksums = FFI_Yajl::Parser.parse(request.body, :create_additions => false)['checksums']
17
- result_checksums = {}
18
- needed_checksums.keys.each do |needed_checksum|
19
- if list_data(request, request.rest_path[0..1] + ['file_store', 'checksums']).include?(needed_checksum)
20
- result_checksums[needed_checksum] = { :needs_upload => false }
21
- else
22
- result_checksums[needed_checksum] = {
23
- :needs_upload => true,
24
- :url => build_uri(request.base_uri, request.rest_path[0..1] + ['file_store', 'checksums', needed_checksum])
25
- }
26
- sandbox_checksums << needed_checksum
27
- end
28
- end
29
-
30
- # There is an obvious race condition here.
31
- id = @next_id.to_s
32
- @next_id+=1
33
-
34
- time_str = Time.now.utc.strftime('%Y-%m-%dT%H:%M:%S%z')
35
- time_str = "#{time_str[0..21]}:#{time_str[22..23]}"
36
-
37
- create_data(request, request.rest_path, id, FFI_Yajl::Encoder.encode({
38
- :create_time => time_str,
39
- :checksums => sandbox_checksums
40
- }, :pretty => true))
41
-
42
- json_response(201, {
43
- :uri => build_uri(request.base_uri, request.rest_path + [id]),
44
- :checksums => result_checksums,
45
- :sandbox_id => id
46
- })
47
- end
48
- end
49
- end
50
- end
1
+ require 'ffi_yajl'
2
+ require 'chef_zero/rest_base'
3
+
4
+ module ChefZero
5
+ module Endpoints
6
+ # /sandboxes
7
+ class SandboxesEndpoint < RestBase
8
+ def initialize(server)
9
+ super(server)
10
+ @next_id = 1
11
+ end
12
+
13
+ def post(request)
14
+ sandbox_checksums = []
15
+
16
+ needed_checksums = FFI_Yajl::Parser.parse(request.body, :create_additions => false)['checksums']
17
+ result_checksums = {}
18
+ needed_checksums.keys.each do |needed_checksum|
19
+ if list_data(request, request.rest_path[0..1] + ['file_store', 'checksums']).include?(needed_checksum)
20
+ result_checksums[needed_checksum] = { :needs_upload => false }
21
+ else
22
+ result_checksums[needed_checksum] = {
23
+ :needs_upload => true,
24
+ :url => build_uri(request.base_uri, request.rest_path[0..1] + ['file_store', 'checksums', needed_checksum])
25
+ }
26
+ sandbox_checksums << needed_checksum
27
+ end
28
+ end
29
+
30
+ # There is an obvious race condition here.
31
+ id = @next_id.to_s
32
+ @next_id+=1
33
+
34
+ time_str = Time.now.utc.strftime('%Y-%m-%dT%H:%M:%S%z')
35
+ time_str = "#{time_str[0..21]}:#{time_str[22..23]}"
36
+
37
+ create_data(request, request.rest_path, id, FFI_Yajl::Encoder.encode({
38
+ :create_time => time_str,
39
+ :checksums => sandbox_checksums
40
+ }, :pretty => true))
41
+
42
+ json_response(201, {
43
+ :uri => build_uri(request.base_uri, request.rest_path + [id]),
44
+ :checksums => result_checksums,
45
+ :sandbox_id => id
46
+ })
47
+ end
48
+ end
49
+ end
50
+ end
@@ -1,192 +1,194 @@
1
- require 'ffi_yajl'
2
- require 'chef_zero/endpoints/rest_object_endpoint'
3
- require 'chef_zero/chef_data/data_normalizer'
4
- require 'chef_zero/rest_error_response'
5
- require 'chef_zero/solr/solr_parser'
6
- require 'chef_zero/solr/solr_doc'
7
-
8
- module ChefZero
9
- module Endpoints
10
- # /search/INDEX
11
- class SearchEndpoint < RestBase
12
- def get(request)
13
- results = search(request)
14
- results['rows'] = results['rows'].map { |name,uri,value,search_value| value }
15
- json_response(200, results)
16
- end
17
-
18
- def post(request)
19
- full_results = search(request)
20
- keys = FFI_Yajl::Parser.parse(request.body, :create_additions => false)
21
- partial_results = full_results['rows'].map do |name, uri, doc, search_value|
22
- data = {}
23
- keys.each_pair do |key, path|
24
- if path.size > 0
25
- value = search_value
26
- path.each do |path_part|
27
- value = value[path_part] if !value.nil?
28
- end
29
- data[key] = value
30
- else
31
- data[key] = nil
32
- end
33
- end
34
- {
35
- 'url' => uri,
36
- 'data' => data
37
- }
38
- end
39
- json_response(200, {
40
- 'rows' => partial_results,
41
- 'start' => full_results['start'],
42
- 'total' => full_results['total']
43
- })
44
- end
45
-
46
- private
47
-
48
- def search_container(request, index)
49
- relative_parts, normalize_proc = case index
50
- when 'client'
51
- [ ['clients'], Proc.new { |client, name| ChefData::DataNormalizer.normalize_client(client, name) } ]
52
- when 'node'
53
- [ ['nodes'], Proc.new { |node, name| ChefData::DataNormalizer.normalize_node(node, name) } ]
54
- when 'environment'
55
- [ ['environments'], Proc.new { |environment, name| ChefData::DataNormalizer.normalize_environment(environment, name) } ]
56
- when 'role'
57
- [ ['roles'], Proc.new { |role, name| ChefData::DataNormalizer.normalize_role(role, name) } ]
58
- else
59
- [ ['data', index], Proc.new { |data_bag_item, id| ChefData::DataNormalizer.normalize_data_bag_item(data_bag_item, index, id, 'DELETE') } ]
60
- end
61
- [
62
- request.rest_path[0..1] + relative_parts,
63
- normalize_proc
64
- ]
65
- end
66
-
67
- def expand_for_indexing(value, index, id)
68
- if index == 'node'
69
- result = {}
70
- deep_merge!(value['default'] || {}, result)
71
- deep_merge!(value['normal'] || {}, result)
72
- deep_merge!(value['override'] || {}, result)
73
- deep_merge!(value['automatic'] || {}, result)
74
- result['recipe'] = []
75
- result['role'] = []
76
- if value['run_list']
77
- value['run_list'].each do |run_list_entry|
78
- if run_list_entry =~ /^(recipe|role)\[(.*)\]/
79
- result[$1] << $2
80
- end
81
- end
82
- end
83
- value.each_pair do |key, value|
84
- result[key] = value unless %w(default normal override automatic).include?(key)
85
- end
86
- result
87
-
88
- elsif !%w(client environment role).include?(index)
89
- ChefData::DataNormalizer.normalize_data_bag_item(value, index, id, 'GET')
90
- else
91
- value
92
- end
93
- end
94
-
95
- def search(request)
96
- # Extract parameters
97
- index = request.rest_path[3]
98
- query_string = request.query_params['q'] || '*:*'
99
- solr_query = ChefZero::Solr::SolrParser.new(query_string).parse
100
- sort_string = request.query_params['sort']
101
- start = request.query_params['start']
102
- start = start.to_i if start
103
- rows = request.query_params['rows']
104
- rows = rows.to_i if rows
105
-
106
- # Get the search container
107
- container, expander = search_container(request, index)
108
-
109
- # Search!
110
- result = []
111
- list_data(request, container).each do |name|
112
- value = get_data(request, container + [name])
113
- expanded = expander.call(FFI_Yajl::Parser.parse(value, :create_additions => false), name)
114
- result << [ name, build_uri(request.base_uri, container + [name]), expanded, expand_for_indexing(expanded, index, name) ]
115
- end
116
- result = result.select do |name, uri, value, search_value|
117
- solr_query.matches_doc?(ChefZero::Solr::SolrDoc.new(search_value, name))
118
- end
119
- total = result.size
120
-
121
- # Sort
122
- if sort_string
123
- sort_key, sort_order = sort_string.split(/\s+/, 2)
124
- result = result.sort_by { |name,uri,value,search_value| ChefZero::Solr::SolrDoc.new(search_value, name)[sort_key] }
125
- result = result.reverse if sort_order == "DESC"
126
- end
127
-
128
- # Paginate
129
- if start
130
- result = result[start..start+(rows||-1)]
131
- end
132
- {
133
- 'rows' => result,
134
- 'start' => start || 0,
135
- 'total' => total
136
- }
137
- end
138
-
139
- private
140
-
141
- # Deep Merge core documentation.
142
- # deep_merge! method permits merging of arbitrary child elements. The two top level
143
- # elements must be hashes. These hashes can contain unlimited (to stack limit) levels
144
- # of child elements. These child elements to not have to be of the same types.
145
- # Where child elements are of the same type, deep_merge will attempt to merge them together.
146
- # Where child elements are not of the same type, deep_merge will skip or optionally overwrite
147
- # the destination element with the contents of the source element at that level.
148
- # So if you have two hashes like this:
149
- # source = {:x => [1,2,3], :y => 2}
150
- # dest = {:x => [4,5,'6'], :y => [7,8,9]}
151
- # dest.deep_merge!(source)
152
- # Results: {:x => [1,2,3,4,5,'6'], :y => 2}
153
- # By default, "deep_merge!" will overwrite any unmergeables and merge everything else.
154
- # To avoid this, use "deep_merge" (no bang/exclamation mark)
155
- def deep_merge!(source, dest)
156
- # if dest doesn't exist, then simply copy source to it
157
- if dest.nil?
158
- dest = source; return dest
159
- end
160
-
161
- case source
162
- when nil
163
- dest
164
- when Hash
165
- source.each do |src_key, src_value|
166
- if dest.kind_of?(Hash)
167
- if dest[src_key]
168
- dest[src_key] = deep_merge!(src_value, dest[src_key])
169
- else # dest[src_key] doesn't exist so we take whatever source has
170
- dest[src_key] = src_value
171
- end
172
- else # dest isn't a hash, so we overwrite it completely
173
- dest = source
174
- end
175
- end
176
- when Array
177
- if dest.kind_of?(Array)
178
- dest = dest | source
179
- else
180
- dest = source
181
- end
182
- when String
183
- dest = source
184
- else # src_hash is not an array or hash, so we'll have to overwrite dest
185
- dest = source
186
- end
187
- dest
188
- end # deep_merge!
189
-
190
- end
191
- end
192
- end
1
+ require 'ffi_yajl'
2
+ require 'chef_zero/endpoints/rest_object_endpoint'
3
+ require 'chef_zero/chef_data/data_normalizer'
4
+ require 'chef_zero/rest_error_response'
5
+ require 'chef_zero/solr/solr_parser'
6
+ require 'chef_zero/solr/solr_doc'
7
+
8
+ module ChefZero
9
+ module Endpoints
10
+ # /search/INDEX
11
+ class SearchEndpoint < RestBase
12
+ def get(request)
13
+ orgname = request.rest_path[1]
14
+ results = search(request, orgname)
15
+ results['rows'] = results['rows'].map { |name,uri,value,search_value| value }
16
+ json_response(200, results)
17
+ end
18
+
19
+ def post(request)
20
+ orgname = request.rest_path[1]
21
+ full_results = search(request, orgname)
22
+ keys = FFI_Yajl::Parser.parse(request.body, :create_additions => false)
23
+ partial_results = full_results['rows'].map do |name, uri, doc, search_value|
24
+ data = {}
25
+ keys.each_pair do |key, path|
26
+ if path.size > 0
27
+ value = search_value
28
+ path.each do |path_part|
29
+ value = value[path_part] if !value.nil?
30
+ end
31
+ data[key] = value
32
+ else
33
+ data[key] = nil
34
+ end
35
+ end
36
+ {
37
+ 'url' => uri,
38
+ 'data' => data
39
+ }
40
+ end
41
+ json_response(200, {
42
+ 'rows' => partial_results,
43
+ 'start' => full_results['start'],
44
+ 'total' => full_results['total']
45
+ })
46
+ end
47
+
48
+ private
49
+
50
+ def search_container(request, index, orgname)
51
+ relative_parts, normalize_proc = case index
52
+ when 'client'
53
+ [ ['clients'], Proc.new { |client, name| ChefData::DataNormalizer.normalize_client(client, name, orgname) } ]
54
+ when 'node'
55
+ [ ['nodes'], Proc.new { |node, name| ChefData::DataNormalizer.normalize_node(node, name) } ]
56
+ when 'environment'
57
+ [ ['environments'], Proc.new { |environment, name| ChefData::DataNormalizer.normalize_environment(environment, name) } ]
58
+ when 'role'
59
+ [ ['roles'], Proc.new { |role, name| ChefData::DataNormalizer.normalize_role(role, name) } ]
60
+ else
61
+ [ ['data', index], Proc.new { |data_bag_item, id| ChefData::DataNormalizer.normalize_data_bag_item(data_bag_item, index, id, 'DELETE') } ]
62
+ end
63
+ [
64
+ request.rest_path[0..1] + relative_parts,
65
+ normalize_proc
66
+ ]
67
+ end
68
+
69
+ def expand_for_indexing(value, index, id)
70
+ if index == 'node'
71
+ result = {}
72
+ deep_merge!(value['default'] || {}, result)
73
+ deep_merge!(value['normal'] || {}, result)
74
+ deep_merge!(value['override'] || {}, result)
75
+ deep_merge!(value['automatic'] || {}, result)
76
+ result['recipe'] = []
77
+ result['role'] = []
78
+ if value['run_list']
79
+ value['run_list'].each do |run_list_entry|
80
+ if run_list_entry =~ /^(recipe|role)\[(.*)\]/
81
+ result[$1] << $2
82
+ end
83
+ end
84
+ end
85
+ value.each_pair do |key, value|
86
+ result[key] = value unless %w(default normal override automatic).include?(key)
87
+ end
88
+ result
89
+
90
+ elsif !%w(client environment role).include?(index)
91
+ ChefData::DataNormalizer.normalize_data_bag_item(value, index, id, 'GET')
92
+ else
93
+ value
94
+ end
95
+ end
96
+
97
+ def search(request, orgname = nil)
98
+ # Extract parameters
99
+ index = request.rest_path[3]
100
+ query_string = request.query_params['q'] || '*:*'
101
+ solr_query = ChefZero::Solr::SolrParser.new(query_string).parse
102
+ sort_string = request.query_params['sort']
103
+ start = request.query_params['start']
104
+ start = start.to_i if start
105
+ rows = request.query_params['rows']
106
+ rows = rows.to_i if rows
107
+
108
+ # Get the search container
109
+ container, expander = search_container(request, index, orgname)
110
+
111
+ # Search!
112
+ result = []
113
+ list_data(request, container).each do |name|
114
+ value = get_data(request, container + [name])
115
+ expanded = expander.call(FFI_Yajl::Parser.parse(value, :create_additions => false), name)
116
+ result << [ name, build_uri(request.base_uri, container + [name]), expanded, expand_for_indexing(expanded, index, name) ]
117
+ end
118
+ result = result.select do |name, uri, value, search_value|
119
+ solr_query.matches_doc?(ChefZero::Solr::SolrDoc.new(search_value, name))
120
+ end
121
+ total = result.size
122
+
123
+ # Sort
124
+ if sort_string
125
+ sort_key, sort_order = sort_string.split(/\s+/, 2)
126
+ result = result.sort_by { |name,uri,value,search_value| ChefZero::Solr::SolrDoc.new(search_value, name)[sort_key] }
127
+ result = result.reverse if sort_order == "DESC"
128
+ end
129
+
130
+ # Paginate
131
+ if start
132
+ result = result[start..start+(rows||-1)]
133
+ end
134
+ {
135
+ 'rows' => result,
136
+ 'start' => start || 0,
137
+ 'total' => total
138
+ }
139
+ end
140
+
141
+ private
142
+
143
+ # Deep Merge core documentation.
144
+ # deep_merge! method permits merging of arbitrary child elements. The two top level
145
+ # elements must be hashes. These hashes can contain unlimited (to stack limit) levels
146
+ # of child elements. These child elements to not have to be of the same types.
147
+ # Where child elements are of the same type, deep_merge will attempt to merge them together.
148
+ # Where child elements are not of the same type, deep_merge will skip or optionally overwrite
149
+ # the destination element with the contents of the source element at that level.
150
+ # So if you have two hashes like this:
151
+ # source = {:x => [1,2,3], :y => 2}
152
+ # dest = {:x => [4,5,'6'], :y => [7,8,9]}
153
+ # dest.deep_merge!(source)
154
+ # Results: {:x => [1,2,3,4,5,'6'], :y => 2}
155
+ # By default, "deep_merge!" will overwrite any unmergeables and merge everything else.
156
+ # To avoid this, use "deep_merge" (no bang/exclamation mark)
157
+ def deep_merge!(source, dest)
158
+ # if dest doesn't exist, then simply copy source to it
159
+ if dest.nil?
160
+ dest = source; return dest
161
+ end
162
+
163
+ case source
164
+ when nil
165
+ dest
166
+ when Hash
167
+ source.each do |src_key, src_value|
168
+ if dest.kind_of?(Hash)
169
+ if dest[src_key]
170
+ dest[src_key] = deep_merge!(src_value, dest[src_key])
171
+ else # dest[src_key] doesn't exist so we take whatever source has
172
+ dest[src_key] = src_value
173
+ end
174
+ else # dest isn't a hash, so we overwrite it completely
175
+ dest = source
176
+ end
177
+ end
178
+ when Array
179
+ if dest.kind_of?(Array)
180
+ dest = dest | source
181
+ else
182
+ dest = source
183
+ end
184
+ when String
185
+ dest = source
186
+ else # src_hash is not an array or hash, so we'll have to overwrite dest
187
+ dest = source
188
+ end
189
+ dest
190
+ end # deep_merge!
191
+
192
+ end
193
+ end
194
+ end