chef-zero 15.0.17 → 15.0.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +36 -31
- data/LICENSE +201 -201
- data/Rakefile +73 -68
- data/bin/chef-zero +111 -111
- data/chef-zero.gemspec +34 -33
- data/lib/chef_zero/chef_data/acl_path.rb +140 -140
- data/lib/chef_zero/chef_data/cookbook_data.rb +237 -237
- data/lib/chef_zero/chef_data/data_normalizer.rb +276 -276
- data/lib/chef_zero/chef_data/default_creator.rb +476 -476
- data/lib/chef_zero/data_store/data_already_exists_error.rb +29 -29
- data/lib/chef_zero/data_store/data_error.rb +32 -32
- data/lib/chef_zero/data_store/data_not_found_error.rb +29 -29
- data/lib/chef_zero/data_store/default_facade.rb +143 -147
- data/lib/chef_zero/data_store/interface_v1.rb +67 -67
- data/lib/chef_zero/data_store/interface_v2.rb +18 -18
- data/lib/chef_zero/data_store/memory_store.rb +33 -33
- data/lib/chef_zero/data_store/memory_store_v2.rb +159 -159
- data/lib/chef_zero/data_store/raw_file_store.rb +143 -143
- data/lib/chef_zero/data_store/v1_to_v2_adapter.rb +150 -150
- data/lib/chef_zero/data_store/v2_to_v1_adapter.rb +105 -105
- data/lib/chef_zero/dist.rb +9 -9
- data/lib/chef_zero/endpoints/acl_endpoint.rb +39 -39
- data/lib/chef_zero/endpoints/acls_endpoint.rb +41 -41
- data/lib/chef_zero/endpoints/actor_default_key_endpoint.rb +78 -78
- data/lib/chef_zero/endpoints/actor_endpoint.rb +184 -184
- data/lib/chef_zero/endpoints/actor_key_endpoint.rb +62 -62
- data/lib/chef_zero/endpoints/actor_keys_endpoint.rb +129 -129
- data/lib/chef_zero/endpoints/actors_endpoint.rb +104 -104
- data/lib/chef_zero/endpoints/authenticate_user_endpoint.rb +32 -32
- data/lib/chef_zero/endpoints/container_endpoint.rb +22 -22
- data/lib/chef_zero/endpoints/containers_endpoint.rb +25 -25
- data/lib/chef_zero/endpoints/controls_endpoint.rb +16 -16
- data/lib/chef_zero/endpoints/cookbook_artifact_endpoint.rb +24 -24
- data/lib/chef_zero/endpoints/cookbook_artifact_identifier_endpoint.rb +68 -68
- data/lib/chef_zero/endpoints/cookbook_artifacts_endpoint.rb +34 -34
- data/lib/chef_zero/endpoints/cookbook_endpoint.rb +39 -39
- data/lib/chef_zero/endpoints/cookbook_version_endpoint.rb +136 -136
- data/lib/chef_zero/endpoints/cookbooks_base.rb +80 -80
- data/lib/chef_zero/endpoints/cookbooks_endpoint.rb +19 -19
- data/lib/chef_zero/endpoints/data_bag_endpoint.rb +45 -45
- data/lib/chef_zero/endpoints/data_bag_item_endpoint.rb +25 -25
- data/lib/chef_zero/endpoints/data_bags_endpoint.rb +23 -23
- data/lib/chef_zero/endpoints/dummy_endpoint.rb +29 -29
- data/lib/chef_zero/endpoints/environment_cookbook_endpoint.rb +24 -24
- data/lib/chef_zero/endpoints/environment_cookbook_versions_endpoint.rb +126 -126
- data/lib/chef_zero/endpoints/environment_cookbooks_endpoint.rb +22 -22
- data/lib/chef_zero/endpoints/environment_endpoint.rb +33 -33
- data/lib/chef_zero/endpoints/environment_nodes_endpoint.rb +23 -23
- data/lib/chef_zero/endpoints/environment_recipes_endpoint.rb +22 -22
- data/lib/chef_zero/endpoints/environment_role_endpoint.rb +36 -36
- data/lib/chef_zero/endpoints/file_store_file_endpoint.rb +22 -22
- data/lib/chef_zero/endpoints/group_endpoint.rb +20 -20
- data/lib/chef_zero/endpoints/groups_endpoint.rb +13 -13
- data/lib/chef_zero/endpoints/license_endpoint.rb +25 -25
- data/lib/chef_zero/endpoints/node_endpoint.rb +34 -34
- data/lib/chef_zero/endpoints/node_identifiers_endpoint.rb +22 -22
- data/lib/chef_zero/endpoints/nodes_endpoint.rb +34 -34
- data/lib/chef_zero/endpoints/not_found_endpoint.rb +11 -11
- data/lib/chef_zero/endpoints/organization_association_request_endpoint.rb +22 -22
- data/lib/chef_zero/endpoints/organization_association_requests_endpoint.rb +30 -30
- data/lib/chef_zero/endpoints/organization_authenticate_user_endpoint.rb +26 -26
- data/lib/chef_zero/endpoints/organization_endpoint.rb +47 -47
- data/lib/chef_zero/endpoints/organization_user_base.rb +15 -15
- data/lib/chef_zero/endpoints/organization_user_default_key_endpoint.rb +16 -16
- data/lib/chef_zero/endpoints/organization_user_endpoint.rb +26 -26
- data/lib/chef_zero/endpoints/organization_user_key_endpoint.rb +17 -17
- data/lib/chef_zero/endpoints/organization_user_keys_endpoint.rb +17 -17
- data/lib/chef_zero/endpoints/organization_users_endpoint.rb +43 -43
- data/lib/chef_zero/endpoints/organization_validator_key_endpoint.rb +20 -20
- data/lib/chef_zero/endpoints/organizations_endpoint.rb +61 -61
- data/lib/chef_zero/endpoints/policies_endpoint.rb +26 -26
- data/lib/chef_zero/endpoints/policy_endpoint.rb +24 -24
- data/lib/chef_zero/endpoints/policy_group_endpoint.rb +46 -46
- data/lib/chef_zero/endpoints/policy_group_policy_endpoint.rb +83 -83
- data/lib/chef_zero/endpoints/policy_groups_endpoint.rb +38 -38
- data/lib/chef_zero/endpoints/policy_revision_endpoint.rb +66 -66
- data/lib/chef_zero/endpoints/policy_revisions_endpoint.rb +15 -15
- data/lib/chef_zero/endpoints/principal_endpoint.rb +55 -55
- data/lib/chef_zero/endpoints/rest_list_endpoint.rb +42 -42
- data/lib/chef_zero/endpoints/rest_object_endpoint.rb +78 -78
- data/lib/chef_zero/endpoints/role_endpoint.rb +16 -16
- data/lib/chef_zero/endpoints/role_environments_endpoint.rb +14 -14
- data/lib/chef_zero/endpoints/sandbox_endpoint.rb +27 -27
- data/lib/chef_zero/endpoints/sandboxes_endpoint.rb +51 -51
- data/lib/chef_zero/endpoints/search_endpoint.rb +208 -208
- data/lib/chef_zero/endpoints/searches_endpoint.rb +18 -18
- data/lib/chef_zero/endpoints/server_api_version_endpoint.rb +14 -14
- data/lib/chef_zero/endpoints/system_recovery_endpoint.rb +30 -30
- data/lib/chef_zero/endpoints/universe_endpoint.rb +15 -15
- data/lib/chef_zero/endpoints/user_association_request_endpoint.rb +41 -41
- data/lib/chef_zero/endpoints/user_association_requests_count_endpoint.rb +19 -19
- data/lib/chef_zero/endpoints/user_association_requests_endpoint.rb +19 -19
- data/lib/chef_zero/endpoints/user_organizations_endpoint.rb +22 -22
- data/lib/chef_zero/endpoints/version_endpoint.rb +13 -13
- data/lib/chef_zero/log.rb +7 -7
- data/lib/chef_zero/rest_base.rb +332 -332
- data/lib/chef_zero/rest_error_response.rb +11 -11
- data/lib/chef_zero/rest_request.rb +84 -88
- data/lib/chef_zero/rest_router.rb +72 -72
- data/lib/chef_zero/rspec.rb +355 -355
- data/lib/chef_zero/server.rb +730 -730
- data/lib/chef_zero/socketless_server_map.rb +92 -93
- data/lib/chef_zero/solr/query/binary_operator.rb +52 -52
- data/lib/chef_zero/solr/query/phrase.rb +23 -23
- data/lib/chef_zero/solr/query/range_query.rb +46 -46
- data/lib/chef_zero/solr/query/regexpable_query.rb +30 -30
- data/lib/chef_zero/solr/query/subquery.rb +37 -37
- data/lib/chef_zero/solr/query/term.rb +45 -45
- data/lib/chef_zero/solr/query/unary_operator.rb +41 -41
- data/lib/chef_zero/solr/solr_doc.rb +53 -53
- data/lib/chef_zero/solr/solr_parser.rb +208 -208
- data/lib/chef_zero/version.rb +3 -3
- data/lib/chef_zero.rb +10 -10
- data/spec/run_oc_pedant.rb +226 -226
- data/spec/search_spec.rb +36 -36
- data/spec/server_spec.rb +96 -96
- data/spec/socketless_server_map_spec.rb +74 -74
- data/spec/support/oc_pedant.rb +149 -149
- data/spec/support/secrets.json +6 -6
- data/spec/support/stickywicket.pem +27 -27
- metadata +35 -18
@@ -1,208 +1,208 @@
|
|
1
|
-
require "ffi_yajl" unless defined?(FFI_Yajl)
|
2
|
-
require_relative "rest_object_endpoint"
|
3
|
-
require_relative "../chef_data/data_normalizer"
|
4
|
-
require_relative "../rest_error_response"
|
5
|
-
require_relative "../solr/solr_parser"
|
6
|
-
require_relative "../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
|
-
|
16
|
-
results["rows"] = results["rows"].map { |name, uri, value, search_value| value }
|
17
|
-
|
18
|
-
json_response(200, results)
|
19
|
-
rescue ChefZero::Solr::ParseError
|
20
|
-
bad_search_request(request)
|
21
|
-
end
|
22
|
-
|
23
|
-
def post(request)
|
24
|
-
orgname = request.rest_path[1]
|
25
|
-
full_results = search(request, orgname)
|
26
|
-
keys = FFI_Yajl::Parser.parse(request.body)
|
27
|
-
partial_results = full_results["rows"].map do |name, uri, doc, search_value|
|
28
|
-
data = {}
|
29
|
-
keys.each_pair do |key, path|
|
30
|
-
if path.size > 0
|
31
|
-
value = search_value
|
32
|
-
path.each do |path_part|
|
33
|
-
value = value[path_part] unless value.nil?
|
34
|
-
end
|
35
|
-
data[key] = value
|
36
|
-
else
|
37
|
-
data[key] = nil
|
38
|
-
end
|
39
|
-
end
|
40
|
-
{
|
41
|
-
"url" => uri,
|
42
|
-
"data" => data,
|
43
|
-
}
|
44
|
-
end
|
45
|
-
json_response(200, {
|
46
|
-
"rows" => partial_results,
|
47
|
-
"start" => full_results["start"],
|
48
|
-
"total" => full_results["total"],
|
49
|
-
})
|
50
|
-
rescue ChefZero::Solr::ParseError
|
51
|
-
bad_search_request(request)
|
52
|
-
end
|
53
|
-
|
54
|
-
private
|
55
|
-
|
56
|
-
def bad_search_request(request)
|
57
|
-
query_string = request.query_params["q"]
|
58
|
-
resp = { "error" => ["invalid search query: '#{query_string}'"] }
|
59
|
-
json_response(400, resp)
|
60
|
-
end
|
61
|
-
|
62
|
-
def search_container(request, index, orgname)
|
63
|
-
relative_parts, normalize_proc =
|
64
|
-
case index
|
65
|
-
when "client"
|
66
|
-
[ ["clients"], Proc.new { |client, name| ChefData::DataNormalizer.normalize_client(client, name, orgname) } ]
|
67
|
-
when "node"
|
68
|
-
[ ["nodes"], Proc.new { |node, name| ChefData::DataNormalizer.normalize_node(node, name) } ]
|
69
|
-
when "environment"
|
70
|
-
[ ["environments"], Proc.new { |environment, name| ChefData::DataNormalizer.normalize_environment(environment, name) } ]
|
71
|
-
when "role"
|
72
|
-
[ ["roles"], Proc.new { |role, name| ChefData::DataNormalizer.normalize_role(role, name) } ]
|
73
|
-
else
|
74
|
-
[ ["data", index], Proc.new { |data_bag_item, id| ChefData::DataNormalizer.normalize_data_bag_item(data_bag_item, index, id, "DELETE") } ]
|
75
|
-
end
|
76
|
-
|
77
|
-
[
|
78
|
-
request.rest_path[0..1] + relative_parts,
|
79
|
-
normalize_proc,
|
80
|
-
]
|
81
|
-
end
|
82
|
-
|
83
|
-
def expand_for_indexing(value, index, id)
|
84
|
-
if index == "node"
|
85
|
-
result = {}
|
86
|
-
deep_merge!(value["default"] || {}, result)
|
87
|
-
deep_merge!(value["normal"] || {}, result)
|
88
|
-
deep_merge!(value["override"] || {}, result)
|
89
|
-
deep_merge!(value["automatic"] || {}, result)
|
90
|
-
result["recipe"] = []
|
91
|
-
result["role"] = []
|
92
|
-
if value["run_list"]
|
93
|
-
value["run_list"].each do |run_list_entry|
|
94
|
-
if run_list_entry =~ /^(recipe|role)\[(.*)\]/
|
95
|
-
result[$1] << $2
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
value.each_pair do |key, val|
|
100
|
-
result[key] = val unless %w{default normal override automatic}.include?(key)
|
101
|
-
end
|
102
|
-
result
|
103
|
-
|
104
|
-
elsif !%w{client environment role}.include?(index)
|
105
|
-
ChefData::DataNormalizer.normalize_data_bag_item(value, index, id, "GET")
|
106
|
-
else
|
107
|
-
value
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
def search(request, orgname = nil)
|
112
|
-
# Extract parameters
|
113
|
-
index = request.rest_path[3]
|
114
|
-
query_string = request.query_params["q"] || "*:*"
|
115
|
-
solr_query = ChefZero::Solr::SolrParser.new(query_string).parse
|
116
|
-
sort_string = request.query_params["sort"]
|
117
|
-
start = request.query_params["start"].to_i
|
118
|
-
rows = request.query_params["rows"].to_i
|
119
|
-
|
120
|
-
# Get the search container
|
121
|
-
container, expander = search_container(request, index, orgname)
|
122
|
-
|
123
|
-
# Search!
|
124
|
-
result = []
|
125
|
-
list_data(request, container).each do |name|
|
126
|
-
value = get_data(request, container + [name])
|
127
|
-
expanded = expander.call(FFI_Yajl::Parser.parse(value), name)
|
128
|
-
result << [ name, build_uri(request.base_uri, container + [name]), expanded, expand_for_indexing(expanded, index, name) ]
|
129
|
-
end
|
130
|
-
result = result.select do |name, uri, value, search_value|
|
131
|
-
solr_query.matches_doc?(ChefZero::Solr::SolrDoc.new(search_value, name))
|
132
|
-
end
|
133
|
-
total = result.size
|
134
|
-
|
135
|
-
# Sort
|
136
|
-
if sort_string
|
137
|
-
sort_key, sort_order = sort_string.split(/\s+/, 2)
|
138
|
-
result = result.sort_by { |name, uri, value, search_value| ChefZero::Solr::SolrDoc.new(search_value, name)[sort_key] }
|
139
|
-
result = result.reverse if sort_order == "DESC"
|
140
|
-
end
|
141
|
-
|
142
|
-
{
|
143
|
-
# Paginate
|
144
|
-
#
|
145
|
-
# Slice the array based on the value of the "rows" query parameter. If
|
146
|
-
# this is a positive integer, we'll get the number of rows asked for.
|
147
|
-
# If it's nil, we'll get -1, which gives us all of the elements.
|
148
|
-
#
|
149
|
-
# Do the same for "start", which will start at 0 if that value is not
|
150
|
-
# given.
|
151
|
-
"rows" => result[start..(rows - 1)],
|
152
|
-
# Also return start and total in the object
|
153
|
-
"start" => start,
|
154
|
-
"total" => total,
|
155
|
-
}
|
156
|
-
end
|
157
|
-
|
158
|
-
# Deep Merge core documentation.
|
159
|
-
# deep_merge! method permits merging of arbitrary child elements. The two top level
|
160
|
-
# elements must be hashes. These hashes can contain unlimited (to stack limit) levels
|
161
|
-
# of child elements. These child elements to not have to be of the same types.
|
162
|
-
# Where child elements are of the same type, deep_merge will attempt to merge them together.
|
163
|
-
# Where child elements are not of the same type, deep_merge will skip or optionally overwrite
|
164
|
-
# the destination element with the contents of the source element at that level.
|
165
|
-
# So if you have two hashes like this:
|
166
|
-
# source = {:x => [1,2,3], :y => 2}
|
167
|
-
# dest = {:x => [4,5,'6'], :y => [7,8,9]}
|
168
|
-
# dest.deep_merge!(source)
|
169
|
-
# Results: {:x => [1,2,3,4,5,'6'], :y => 2}
|
170
|
-
# By default, "deep_merge!" will overwrite any unmergeables and merge everything else.
|
171
|
-
# To avoid this, use "deep_merge" (no bang/exclamation mark)
|
172
|
-
def deep_merge!(source, dest)
|
173
|
-
# if dest doesn't exist, then simply copy source to it
|
174
|
-
if dest.nil?
|
175
|
-
dest = source; return dest
|
176
|
-
end
|
177
|
-
|
178
|
-
case source
|
179
|
-
when nil
|
180
|
-
dest
|
181
|
-
when Hash
|
182
|
-
source.each do |src_key, src_value|
|
183
|
-
if dest.is_a?(Hash)
|
184
|
-
if dest[src_key]
|
185
|
-
dest[src_key] = deep_merge!(src_value, dest[src_key])
|
186
|
-
else # dest[src_key] doesn't exist so we take whatever source has
|
187
|
-
dest[src_key] = src_value
|
188
|
-
end
|
189
|
-
else # dest isn't a hash, so we overwrite it completely
|
190
|
-
dest = source
|
191
|
-
end
|
192
|
-
end
|
193
|
-
when Array
|
194
|
-
if dest.is_a?(Array)
|
195
|
-
dest |= source
|
196
|
-
else
|
197
|
-
dest = source
|
198
|
-
end
|
199
|
-
when String
|
200
|
-
dest = source
|
201
|
-
else # src_hash is not an array or hash, so we'll have to overwrite dest
|
202
|
-
dest = source
|
203
|
-
end
|
204
|
-
dest
|
205
|
-
end # deep_merge!
|
206
|
-
end
|
207
|
-
end
|
208
|
-
end
|
1
|
+
require "ffi_yajl" unless defined?(FFI_Yajl)
|
2
|
+
require_relative "rest_object_endpoint"
|
3
|
+
require_relative "../chef_data/data_normalizer"
|
4
|
+
require_relative "../rest_error_response"
|
5
|
+
require_relative "../solr/solr_parser"
|
6
|
+
require_relative "../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
|
+
|
16
|
+
results["rows"] = results["rows"].map { |name, uri, value, search_value| value }
|
17
|
+
|
18
|
+
json_response(200, results)
|
19
|
+
rescue ChefZero::Solr::ParseError
|
20
|
+
bad_search_request(request)
|
21
|
+
end
|
22
|
+
|
23
|
+
def post(request)
|
24
|
+
orgname = request.rest_path[1]
|
25
|
+
full_results = search(request, orgname)
|
26
|
+
keys = FFI_Yajl::Parser.parse(request.body)
|
27
|
+
partial_results = full_results["rows"].map do |name, uri, doc, search_value|
|
28
|
+
data = {}
|
29
|
+
keys.each_pair do |key, path|
|
30
|
+
if path.size > 0
|
31
|
+
value = search_value
|
32
|
+
path.each do |path_part|
|
33
|
+
value = value[path_part] unless value.nil?
|
34
|
+
end
|
35
|
+
data[key] = value
|
36
|
+
else
|
37
|
+
data[key] = nil
|
38
|
+
end
|
39
|
+
end
|
40
|
+
{
|
41
|
+
"url" => uri,
|
42
|
+
"data" => data,
|
43
|
+
}
|
44
|
+
end
|
45
|
+
json_response(200, {
|
46
|
+
"rows" => partial_results,
|
47
|
+
"start" => full_results["start"],
|
48
|
+
"total" => full_results["total"],
|
49
|
+
})
|
50
|
+
rescue ChefZero::Solr::ParseError
|
51
|
+
bad_search_request(request)
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def bad_search_request(request)
|
57
|
+
query_string = request.query_params["q"]
|
58
|
+
resp = { "error" => ["invalid search query: '#{query_string}'"] }
|
59
|
+
json_response(400, resp)
|
60
|
+
end
|
61
|
+
|
62
|
+
def search_container(request, index, orgname)
|
63
|
+
relative_parts, normalize_proc =
|
64
|
+
case index
|
65
|
+
when "client"
|
66
|
+
[ ["clients"], Proc.new { |client, name| ChefData::DataNormalizer.normalize_client(client, name, orgname) } ]
|
67
|
+
when "node"
|
68
|
+
[ ["nodes"], Proc.new { |node, name| ChefData::DataNormalizer.normalize_node(node, name) } ]
|
69
|
+
when "environment"
|
70
|
+
[ ["environments"], Proc.new { |environment, name| ChefData::DataNormalizer.normalize_environment(environment, name) } ]
|
71
|
+
when "role"
|
72
|
+
[ ["roles"], Proc.new { |role, name| ChefData::DataNormalizer.normalize_role(role, name) } ]
|
73
|
+
else
|
74
|
+
[ ["data", index], Proc.new { |data_bag_item, id| ChefData::DataNormalizer.normalize_data_bag_item(data_bag_item, index, id, "DELETE") } ]
|
75
|
+
end
|
76
|
+
|
77
|
+
[
|
78
|
+
request.rest_path[0..1] + relative_parts,
|
79
|
+
normalize_proc,
|
80
|
+
]
|
81
|
+
end
|
82
|
+
|
83
|
+
def expand_for_indexing(value, index, id)
|
84
|
+
if index == "node"
|
85
|
+
result = {}
|
86
|
+
deep_merge!(value["default"] || {}, result)
|
87
|
+
deep_merge!(value["normal"] || {}, result)
|
88
|
+
deep_merge!(value["override"] || {}, result)
|
89
|
+
deep_merge!(value["automatic"] || {}, result)
|
90
|
+
result["recipe"] = []
|
91
|
+
result["role"] = []
|
92
|
+
if value["run_list"]
|
93
|
+
value["run_list"].each do |run_list_entry|
|
94
|
+
if run_list_entry =~ /^(recipe|role)\[(.*)\]/
|
95
|
+
result[$1] << $2
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
value.each_pair do |key, val|
|
100
|
+
result[key] = val unless %w{default normal override automatic}.include?(key)
|
101
|
+
end
|
102
|
+
result
|
103
|
+
|
104
|
+
elsif !%w{client environment role}.include?(index)
|
105
|
+
ChefData::DataNormalizer.normalize_data_bag_item(value, index, id, "GET")
|
106
|
+
else
|
107
|
+
value
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def search(request, orgname = nil)
|
112
|
+
# Extract parameters
|
113
|
+
index = request.rest_path[3]
|
114
|
+
query_string = request.query_params["q"] || "*:*"
|
115
|
+
solr_query = ChefZero::Solr::SolrParser.new(query_string).parse
|
116
|
+
sort_string = request.query_params["sort"]
|
117
|
+
start = request.query_params["start"].to_i
|
118
|
+
rows = request.query_params["rows"].to_i
|
119
|
+
|
120
|
+
# Get the search container
|
121
|
+
container, expander = search_container(request, index, orgname)
|
122
|
+
|
123
|
+
# Search!
|
124
|
+
result = []
|
125
|
+
list_data(request, container).each do |name|
|
126
|
+
value = get_data(request, container + [name])
|
127
|
+
expanded = expander.call(FFI_Yajl::Parser.parse(value), name)
|
128
|
+
result << [ name, build_uri(request.base_uri, container + [name]), expanded, expand_for_indexing(expanded, index, name) ]
|
129
|
+
end
|
130
|
+
result = result.select do |name, uri, value, search_value|
|
131
|
+
solr_query.matches_doc?(ChefZero::Solr::SolrDoc.new(search_value, name))
|
132
|
+
end
|
133
|
+
total = result.size
|
134
|
+
|
135
|
+
# Sort
|
136
|
+
if sort_string
|
137
|
+
sort_key, sort_order = sort_string.split(/\s+/, 2)
|
138
|
+
result = result.sort_by { |name, uri, value, search_value| ChefZero::Solr::SolrDoc.new(search_value, name)[sort_key] }
|
139
|
+
result = result.reverse if sort_order == "DESC"
|
140
|
+
end
|
141
|
+
|
142
|
+
{
|
143
|
+
# Paginate
|
144
|
+
#
|
145
|
+
# Slice the array based on the value of the "rows" query parameter. If
|
146
|
+
# this is a positive integer, we'll get the number of rows asked for.
|
147
|
+
# If it's nil, we'll get -1, which gives us all of the elements.
|
148
|
+
#
|
149
|
+
# Do the same for "start", which will start at 0 if that value is not
|
150
|
+
# given.
|
151
|
+
"rows" => result[start..(rows - 1)],
|
152
|
+
# Also return start and total in the object
|
153
|
+
"start" => start,
|
154
|
+
"total" => total,
|
155
|
+
}
|
156
|
+
end
|
157
|
+
|
158
|
+
# Deep Merge core documentation.
|
159
|
+
# deep_merge! method permits merging of arbitrary child elements. The two top level
|
160
|
+
# elements must be hashes. These hashes can contain unlimited (to stack limit) levels
|
161
|
+
# of child elements. These child elements to not have to be of the same types.
|
162
|
+
# Where child elements are of the same type, deep_merge will attempt to merge them together.
|
163
|
+
# Where child elements are not of the same type, deep_merge will skip or optionally overwrite
|
164
|
+
# the destination element with the contents of the source element at that level.
|
165
|
+
# So if you have two hashes like this:
|
166
|
+
# source = {:x => [1,2,3], :y => 2}
|
167
|
+
# dest = {:x => [4,5,'6'], :y => [7,8,9]}
|
168
|
+
# dest.deep_merge!(source)
|
169
|
+
# Results: {:x => [1,2,3,4,5,'6'], :y => 2}
|
170
|
+
# By default, "deep_merge!" will overwrite any unmergeables and merge everything else.
|
171
|
+
# To avoid this, use "deep_merge" (no bang/exclamation mark)
|
172
|
+
def deep_merge!(source, dest)
|
173
|
+
# if dest doesn't exist, then simply copy source to it
|
174
|
+
if dest.nil?
|
175
|
+
dest = source; return dest
|
176
|
+
end
|
177
|
+
|
178
|
+
case source
|
179
|
+
when nil
|
180
|
+
dest
|
181
|
+
when Hash
|
182
|
+
source.each do |src_key, src_value|
|
183
|
+
if dest.is_a?(Hash)
|
184
|
+
if dest[src_key]
|
185
|
+
dest[src_key] = deep_merge!(src_value, dest[src_key])
|
186
|
+
else # dest[src_key] doesn't exist so we take whatever source has
|
187
|
+
dest[src_key] = src_value
|
188
|
+
end
|
189
|
+
else # dest isn't a hash, so we overwrite it completely
|
190
|
+
dest = source
|
191
|
+
end
|
192
|
+
end
|
193
|
+
when Array
|
194
|
+
if dest.is_a?(Array)
|
195
|
+
dest |= source
|
196
|
+
else
|
197
|
+
dest = source
|
198
|
+
end
|
199
|
+
when String
|
200
|
+
dest = source
|
201
|
+
else # src_hash is not an array or hash, so we'll have to overwrite dest
|
202
|
+
dest = source
|
203
|
+
end
|
204
|
+
dest
|
205
|
+
end # deep_merge!
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
@@ -1,18 +1,18 @@
|
|
1
|
-
require_relative "../rest_base"
|
2
|
-
|
3
|
-
module ChefZero
|
4
|
-
module Endpoints
|
5
|
-
# /search
|
6
|
-
class SearchesEndpoint < RestBase
|
7
|
-
def get(request)
|
8
|
-
# Get the result
|
9
|
-
result_hash = {}
|
10
|
-
indices = (%w{client environment node role} + data_store.list(request.rest_path[0..1] + ["data"])).sort
|
11
|
-
indices.each do |index|
|
12
|
-
result_hash[index] = build_uri(request.base_uri, request.rest_path + [index])
|
13
|
-
end
|
14
|
-
json_response(200, result_hash)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
1
|
+
require_relative "../rest_base"
|
2
|
+
|
3
|
+
module ChefZero
|
4
|
+
module Endpoints
|
5
|
+
# /search
|
6
|
+
class SearchesEndpoint < RestBase
|
7
|
+
def get(request)
|
8
|
+
# Get the result
|
9
|
+
result_hash = {}
|
10
|
+
indices = (%w{client environment node role} + data_store.list(request.rest_path[0..1] + ["data"])).sort
|
11
|
+
indices.each do |index|
|
12
|
+
result_hash[index] = build_uri(request.base_uri, request.rest_path + [index])
|
13
|
+
end
|
14
|
+
json_response(200, result_hash)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -1,14 +1,14 @@
|
|
1
|
-
require_relative "../rest_base"
|
2
|
-
|
3
|
-
module ChefZero
|
4
|
-
module Endpoints
|
5
|
-
# /server_api_version
|
6
|
-
class ServerAPIVersionEndpoint < RestBase
|
7
|
-
API_VERSION = 2
|
8
|
-
def get(request)
|
9
|
-
json_response(200, { "min_api_version" => MIN_API_VERSION, "max_api_version" => MAX_API_VERSION },
|
10
|
-
request_version: request.api_version, response_version: API_VERSION)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
1
|
+
require_relative "../rest_base"
|
2
|
+
|
3
|
+
module ChefZero
|
4
|
+
module Endpoints
|
5
|
+
# /server_api_version
|
6
|
+
class ServerAPIVersionEndpoint < RestBase
|
7
|
+
API_VERSION = 2
|
8
|
+
def get(request)
|
9
|
+
json_response(200, { "min_api_version" => MIN_API_VERSION, "max_api_version" => MAX_API_VERSION },
|
10
|
+
request_version: request.api_version, response_version: API_VERSION)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -1,30 +1,30 @@
|
|
1
|
-
require "ffi_yajl" unless defined?(FFI_Yajl)
|
2
|
-
require_relative "../rest_base"
|
3
|
-
|
4
|
-
module ChefZero
|
5
|
-
module Endpoints
|
6
|
-
# /system_recovery
|
7
|
-
class SystemRecoveryEndpoint < RestBase
|
8
|
-
def post(request)
|
9
|
-
request_json = FFI_Yajl::Parser.parse(request.body)
|
10
|
-
name = request_json["username"]
|
11
|
-
password = request_json["password"]
|
12
|
-
user = get_data(request, request.rest_path[0..-2] + ["users", name], :nil)
|
13
|
-
unless user
|
14
|
-
raise RestErrorResponse.new(403, "Nonexistent user")
|
15
|
-
end
|
16
|
-
|
17
|
-
user = FFI_Yajl::Parser.parse(user)
|
18
|
-
user = ChefData::DataNormalizer.normalize_user(user, name, [ "username" ], server.options[:osc_compat])
|
19
|
-
unless user["recovery_authentication_enabled"]
|
20
|
-
raise RestErrorResponse.new(403, "Only users with recovery_authentication_enabled=true may use /system_recovery to log in")
|
21
|
-
end
|
22
|
-
if user["password"] != password
|
23
|
-
raise RestErrorResponse.new(401, "Incorrect password")
|
24
|
-
end
|
25
|
-
|
26
|
-
json_response(200, user)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
1
|
+
require "ffi_yajl" unless defined?(FFI_Yajl)
|
2
|
+
require_relative "../rest_base"
|
3
|
+
|
4
|
+
module ChefZero
|
5
|
+
module Endpoints
|
6
|
+
# /system_recovery
|
7
|
+
class SystemRecoveryEndpoint < RestBase
|
8
|
+
def post(request)
|
9
|
+
request_json = FFI_Yajl::Parser.parse(request.body)
|
10
|
+
name = request_json["username"]
|
11
|
+
password = request_json["password"]
|
12
|
+
user = get_data(request, request.rest_path[0..-2] + ["users", name], :nil)
|
13
|
+
unless user
|
14
|
+
raise RestErrorResponse.new(403, "Nonexistent user")
|
15
|
+
end
|
16
|
+
|
17
|
+
user = FFI_Yajl::Parser.parse(user)
|
18
|
+
user = ChefData::DataNormalizer.normalize_user(user, name, [ "username" ], server.options[:osc_compat])
|
19
|
+
unless user["recovery_authentication_enabled"]
|
20
|
+
raise RestErrorResponse.new(403, "Only users with recovery_authentication_enabled=true may use /system_recovery to log in")
|
21
|
+
end
|
22
|
+
if user["password"] != password
|
23
|
+
raise RestErrorResponse.new(401, "Incorrect password")
|
24
|
+
end
|
25
|
+
|
26
|
+
json_response(200, user)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -1,15 +1,15 @@
|
|
1
|
-
require "ffi_yajl" unless defined?(FFI_Yajl)
|
2
|
-
require_relative "rest_object_endpoint"
|
3
|
-
require_relative "../chef_data/data_normalizer"
|
4
|
-
|
5
|
-
module ChefZero
|
6
|
-
module Endpoints
|
7
|
-
# /universe
|
8
|
-
class UniverseEndpoint < CookbooksBase
|
9
|
-
|
10
|
-
def get(request)
|
11
|
-
json_response(200, format_universe_list(request, all_cookbooks_list(request)))
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
1
|
+
require "ffi_yajl" unless defined?(FFI_Yajl)
|
2
|
+
require_relative "rest_object_endpoint"
|
3
|
+
require_relative "../chef_data/data_normalizer"
|
4
|
+
|
5
|
+
module ChefZero
|
6
|
+
module Endpoints
|
7
|
+
# /universe
|
8
|
+
class UniverseEndpoint < CookbooksBase
|
9
|
+
|
10
|
+
def get(request)
|
11
|
+
json_response(200, format_universe_list(request, all_cookbooks_list(request)))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -1,41 +1,41 @@
|
|
1
|
-
require "ffi_yajl" unless defined?(FFI_Yajl)
|
2
|
-
require_relative "../rest_base"
|
3
|
-
|
4
|
-
module ChefZero
|
5
|
-
module Endpoints
|
6
|
-
# /users/USER/association_requests/ID
|
7
|
-
class UserAssociationRequestEndpoint < RestBase
|
8
|
-
def put(request)
|
9
|
-
username = request.rest_path[1]
|
10
|
-
id = request.rest_path[3]
|
11
|
-
if id !~ /^#{username}-(.+)/
|
12
|
-
raise RestErrorResponse.new(400, "Association request #{id} is invalid. Must be #{username}-orgname.")
|
13
|
-
end
|
14
|
-
|
15
|
-
orgname = $1
|
16
|
-
|
17
|
-
json = FFI_Yajl::Parser.parse(request.body)
|
18
|
-
association_request_path = [ "organizations", orgname, "association_requests", username ]
|
19
|
-
if json["response"] == "accept"
|
20
|
-
users = get_data(request, [ "organizations", orgname, "groups", "users" ])
|
21
|
-
users = FFI_Yajl::Parser.parse(users)
|
22
|
-
|
23
|
-
delete_data(request, association_request_path)
|
24
|
-
create_data(request, [ "organizations", orgname, "users" ], username, "{}")
|
25
|
-
|
26
|
-
# Add the user to the users group if it isn't already there
|
27
|
-
if !users["users"] || !users["users"].include?(username)
|
28
|
-
users["users"] ||= []
|
29
|
-
users["users"] |= [ username ]
|
30
|
-
set_data(request, [ "organizations", orgname, "groups", "users" ], FFI_Yajl::Encoder.encode(users, pretty: true))
|
31
|
-
end
|
32
|
-
elsif json["response"] == "reject"
|
33
|
-
delete_data(request, association_request_path)
|
34
|
-
else
|
35
|
-
raise RestErrorResponse.new(400, "response parameter was missing or set to the wrong value (must be accept or reject)")
|
36
|
-
end
|
37
|
-
json_response(200, { "organization" => { "name" => orgname } })
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
1
|
+
require "ffi_yajl" unless defined?(FFI_Yajl)
|
2
|
+
require_relative "../rest_base"
|
3
|
+
|
4
|
+
module ChefZero
|
5
|
+
module Endpoints
|
6
|
+
# /users/USER/association_requests/ID
|
7
|
+
class UserAssociationRequestEndpoint < RestBase
|
8
|
+
def put(request)
|
9
|
+
username = request.rest_path[1]
|
10
|
+
id = request.rest_path[3]
|
11
|
+
if id !~ /^#{username}-(.+)/
|
12
|
+
raise RestErrorResponse.new(400, "Association request #{id} is invalid. Must be #{username}-orgname.")
|
13
|
+
end
|
14
|
+
|
15
|
+
orgname = $1
|
16
|
+
|
17
|
+
json = FFI_Yajl::Parser.parse(request.body)
|
18
|
+
association_request_path = [ "organizations", orgname, "association_requests", username ]
|
19
|
+
if json["response"] == "accept"
|
20
|
+
users = get_data(request, [ "organizations", orgname, "groups", "users" ])
|
21
|
+
users = FFI_Yajl::Parser.parse(users)
|
22
|
+
|
23
|
+
delete_data(request, association_request_path)
|
24
|
+
create_data(request, [ "organizations", orgname, "users" ], username, "{}")
|
25
|
+
|
26
|
+
# Add the user to the users group if it isn't already there
|
27
|
+
if !users["users"] || !users["users"].include?(username)
|
28
|
+
users["users"] ||= []
|
29
|
+
users["users"] |= [ username ]
|
30
|
+
set_data(request, [ "organizations", orgname, "groups", "users" ], FFI_Yajl::Encoder.encode(users, pretty: true))
|
31
|
+
end
|
32
|
+
elsif json["response"] == "reject"
|
33
|
+
delete_data(request, association_request_path)
|
34
|
+
else
|
35
|
+
raise RestErrorResponse.new(400, "response parameter was missing or set to the wrong value (must be accept or reject)")
|
36
|
+
end
|
37
|
+
json_response(200, { "organization" => { "name" => orgname } })
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|