chef-zero 1.4.0.alpha-x86-mingw32
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.
- data/LICENSE +201 -0
- data/README.md +145 -0
- data/Rakefile +11 -0
- data/bin/chef-zero +43 -0
- data/lib/chef_zero.rb +7 -0
- data/lib/chef_zero/cookbook_data.rb +223 -0
- data/lib/chef_zero/data_normalizer.rb +142 -0
- data/lib/chef_zero/data_store/data_already_exists_error.rb +29 -0
- data/lib/chef_zero/data_store/data_error.rb +31 -0
- data/lib/chef_zero/data_store/data_not_found_error.rb +29 -0
- data/lib/chef_zero/data_store/memory_store.rb +167 -0
- data/lib/chef_zero/endpoints/actor_endpoint.rb +68 -0
- data/lib/chef_zero/endpoints/actors_endpoint.rb +32 -0
- data/lib/chef_zero/endpoints/authenticate_user_endpoint.rb +25 -0
- data/lib/chef_zero/endpoints/cookbook_endpoint.rb +39 -0
- data/lib/chef_zero/endpoints/cookbook_version_endpoint.rb +110 -0
- data/lib/chef_zero/endpoints/cookbooks_base.rb +65 -0
- data/lib/chef_zero/endpoints/cookbooks_endpoint.rb +19 -0
- data/lib/chef_zero/endpoints/data_bag_endpoint.rb +45 -0
- data/lib/chef_zero/endpoints/data_bag_item_endpoint.rb +25 -0
- data/lib/chef_zero/endpoints/data_bags_endpoint.rb +22 -0
- data/lib/chef_zero/endpoints/environment_cookbook_endpoint.rb +24 -0
- data/lib/chef_zero/endpoints/environment_cookbook_versions_endpoint.rb +109 -0
- data/lib/chef_zero/endpoints/environment_cookbooks_endpoint.rb +22 -0
- data/lib/chef_zero/endpoints/environment_endpoint.rb +33 -0
- data/lib/chef_zero/endpoints/environment_nodes_endpoint.rb +23 -0
- data/lib/chef_zero/endpoints/environment_recipes_endpoint.rb +22 -0
- data/lib/chef_zero/endpoints/environment_role_endpoint.rb +36 -0
- data/lib/chef_zero/endpoints/file_store_file_endpoint.rb +22 -0
- data/lib/chef_zero/endpoints/node_endpoint.rb +17 -0
- data/lib/chef_zero/endpoints/not_found_endpoint.rb +11 -0
- data/lib/chef_zero/endpoints/principal_endpoint.rb +30 -0
- data/lib/chef_zero/endpoints/rest_list_endpoint.rb +40 -0
- data/lib/chef_zero/endpoints/rest_object_endpoint.rb +61 -0
- data/lib/chef_zero/endpoints/role_endpoint.rb +16 -0
- data/lib/chef_zero/endpoints/role_environments_endpoint.rb +14 -0
- data/lib/chef_zero/endpoints/sandbox_endpoint.rb +27 -0
- data/lib/chef_zero/endpoints/sandboxes_endpoint.rb +51 -0
- data/lib/chef_zero/endpoints/search_endpoint.rb +188 -0
- data/lib/chef_zero/endpoints/searches_endpoint.rb +18 -0
- data/lib/chef_zero/log.rb +7 -0
- data/lib/chef_zero/rest_base.rb +133 -0
- data/lib/chef_zero/rest_error_response.rb +11 -0
- data/lib/chef_zero/rest_request.rb +56 -0
- data/lib/chef_zero/rest_router.rb +44 -0
- data/lib/chef_zero/rspec.rb +107 -0
- data/lib/chef_zero/server.rb +309 -0
- data/lib/chef_zero/solr/query/binary_operator.rb +53 -0
- data/lib/chef_zero/solr/query/phrase.rb +23 -0
- data/lib/chef_zero/solr/query/range_query.rb +34 -0
- data/lib/chef_zero/solr/query/regexpable_query.rb +29 -0
- data/lib/chef_zero/solr/query/subquery.rb +35 -0
- data/lib/chef_zero/solr/query/term.rb +45 -0
- data/lib/chef_zero/solr/query/unary_operator.rb +43 -0
- data/lib/chef_zero/solr/solr_doc.rb +62 -0
- data/lib/chef_zero/solr/solr_parser.rb +193 -0
- data/lib/chef_zero/version.rb +3 -0
- data/spec/run.rb +25 -0
- data/spec/support/pedant.rb +117 -0
- data/spec/support/stickywicket.pem +27 -0
- metadata +204 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'chef_zero/endpoints/cookbooks_base'
|
3
|
+
|
4
|
+
module ChefZero
|
5
|
+
module Endpoints
|
6
|
+
# /environments/NAME/cookbooks
|
7
|
+
class EnvironmentCookbooksEndpoint < CookbooksBase
|
8
|
+
def get(request)
|
9
|
+
environment = JSON.parse(get_data(request, request.rest_path[0..1]), :create_additions => false)
|
10
|
+
constraints = environment['cookbook_versions'] || {}
|
11
|
+
if request.query_params['num_versions'] == 'all'
|
12
|
+
num_versions = nil
|
13
|
+
elsif request.query_params['num_versions']
|
14
|
+
num_versions = request.query_params['num_versions'].to_i
|
15
|
+
else
|
16
|
+
num_versions = 1
|
17
|
+
end
|
18
|
+
json_response(200, format_cookbooks_list(request, all_cookbooks_list, constraints, num_versions))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'chef_zero/endpoints/rest_object_endpoint'
|
3
|
+
require 'chef_zero/data_normalizer'
|
4
|
+
|
5
|
+
module ChefZero
|
6
|
+
module Endpoints
|
7
|
+
# /environments/NAME
|
8
|
+
class EnvironmentEndpoint < RestObjectEndpoint
|
9
|
+
def delete(request)
|
10
|
+
if request.rest_path[1] == "_default"
|
11
|
+
# 405, really?
|
12
|
+
error(405, "The '_default' environment cannot be modified.")
|
13
|
+
else
|
14
|
+
super(request)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def put(request)
|
19
|
+
if request.rest_path[1] == "_default"
|
20
|
+
error(405, "The '_default' environment cannot be modified.")
|
21
|
+
else
|
22
|
+
super(request)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def populate_defaults(request, response_json)
|
27
|
+
response = JSON.parse(response_json, :create_additions => false)
|
28
|
+
response = DataNormalizer.normalize_environment(response, request.rest_path[1])
|
29
|
+
JSON.pretty_generate(response)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'chef_zero/rest_base'
|
3
|
+
|
4
|
+
module ChefZero
|
5
|
+
module Endpoints
|
6
|
+
# /environment/NAME/nodes
|
7
|
+
class EnvironmentNodesEndpoint < RestBase
|
8
|
+
def get(request)
|
9
|
+
# 404 if environment does not exist
|
10
|
+
get_data(request, request.rest_path[0..1])
|
11
|
+
|
12
|
+
result = {}
|
13
|
+
list_data(request, ['nodes']).each do |name|
|
14
|
+
node = JSON.parse(get_data(request, ['nodes', name]), :create_additions => false)
|
15
|
+
if node['chef_environment'] == request.rest_path[1]
|
16
|
+
result[name] = build_uri(request.base_uri, 'nodes', name)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
json_response(200, result)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'chef_zero/endpoints/cookbooks_base'
|
3
|
+
|
4
|
+
module ChefZero
|
5
|
+
module Endpoints
|
6
|
+
# /environment/NAME/recipes
|
7
|
+
class EnvironmentRecipesEndpoint < CookbooksBase
|
8
|
+
def get(request)
|
9
|
+
environment = JSON.parse(get_data(request, request.rest_path[0..1]), :create_additions => false)
|
10
|
+
constraints = environment['cookbook_versions'] || {}
|
11
|
+
result = []
|
12
|
+
filter_cookbooks(all_cookbooks_list, constraints, 1) do |name, versions|
|
13
|
+
if versions.size > 0
|
14
|
+
cookbook = JSON.parse(get_data(request, ['cookbooks', name, versions[0]]), :create_additions => false)
|
15
|
+
result += recipe_names(name, cookbook)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
json_response(200, result.sort)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'chef_zero/endpoints/cookbooks_base'
|
3
|
+
|
4
|
+
module ChefZero
|
5
|
+
module Endpoints
|
6
|
+
# /environments/NAME/roles/NAME
|
7
|
+
# /roles/NAME/environments/NAME
|
8
|
+
class EnvironmentRoleEndpoint < CookbooksBase
|
9
|
+
def get(request)
|
10
|
+
# 404 if environment does not exist
|
11
|
+
if request.rest_path[0] == 'environments'
|
12
|
+
environment_path = request.rest_path[0..1]
|
13
|
+
role_path = request.rest_path[2..3]
|
14
|
+
else
|
15
|
+
environment_path = request.rest_path[2..3]
|
16
|
+
role_path = request.rest_path[0..1]
|
17
|
+
end
|
18
|
+
# Verify that the environment exists
|
19
|
+
get_data(request, environment_path)
|
20
|
+
|
21
|
+
role = JSON.parse(get_data(request, role_path), :create_additions => false)
|
22
|
+
environment_name = environment_path[1]
|
23
|
+
if environment_name == '_default'
|
24
|
+
run_list = role['run_list']
|
25
|
+
else
|
26
|
+
if role['env_run_lists']
|
27
|
+
run_list = role['env_run_lists'][environment_name]
|
28
|
+
else
|
29
|
+
run_list = nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
json_response(200, { 'run_list' => run_list })
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'chef_zero/rest_base'
|
2
|
+
|
3
|
+
module ChefZero
|
4
|
+
module Endpoints
|
5
|
+
# The minimum amount of S3 necessary to support cookbook upload/download
|
6
|
+
# /file_store/FILE
|
7
|
+
class FileStoreFileEndpoint < RestBase
|
8
|
+
def json_only
|
9
|
+
false
|
10
|
+
end
|
11
|
+
|
12
|
+
def get(request)
|
13
|
+
[200, {"Content-Type" => 'application/x-binary'}, get_data(request) ]
|
14
|
+
end
|
15
|
+
|
16
|
+
def put(request)
|
17
|
+
data_store.set(request.rest_path, request.body, :create, :create_dir)
|
18
|
+
json_response(200, {})
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'chef_zero/endpoints/rest_object_endpoint'
|
3
|
+
require 'chef_zero/data_normalizer'
|
4
|
+
|
5
|
+
module ChefZero
|
6
|
+
module Endpoints
|
7
|
+
# /nodes/ID
|
8
|
+
class NodeEndpoint < RestObjectEndpoint
|
9
|
+
def populate_defaults(request, response_json)
|
10
|
+
node = JSON.parse(response_json, :create_additions => false)
|
11
|
+
node = DataNormalizer.normalize_node(node, request.rest_path[1])
|
12
|
+
JSON.pretty_generate(node)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module ChefZero
|
4
|
+
module Endpoints
|
5
|
+
class NotFoundEndpoint
|
6
|
+
def call(request)
|
7
|
+
return [404, {"Content-Type" => "application/json"}, JSON.pretty_generate({"error" => ["Object not found: #{request.env['REQUEST_PATH']}"]})]
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'chef_zero'
|
3
|
+
require 'chef_zero/rest_base'
|
4
|
+
|
5
|
+
module ChefZero
|
6
|
+
module Endpoints
|
7
|
+
# /principals/NAME
|
8
|
+
class PrincipalEndpoint < RestBase
|
9
|
+
def get(request)
|
10
|
+
name = request.rest_path[-1]
|
11
|
+
json = get_data(request, [ 'users', name ], :nil)
|
12
|
+
if json
|
13
|
+
type = 'user'
|
14
|
+
else
|
15
|
+
json = get_data(request, [ 'clients', name ], :nil)
|
16
|
+
type = 'client'
|
17
|
+
end
|
18
|
+
if json
|
19
|
+
json_response(200, {
|
20
|
+
'name' => name,
|
21
|
+
'type' => type,
|
22
|
+
'public_key' => JSON.parse(json)['public_key'] || PUBLIC_KEY
|
23
|
+
})
|
24
|
+
else
|
25
|
+
error(404, 'Principal not found')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'json'
|
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_key = 'name')
|
9
|
+
super(server)
|
10
|
+
@identity_key = identity_key
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :identity_key
|
14
|
+
|
15
|
+
def get(request)
|
16
|
+
# Get the result
|
17
|
+
result_hash = {}
|
18
|
+
list_data(request).sort.each do |name|
|
19
|
+
result_hash[name] = "#{build_uri(request.base_uri, request.rest_path + [name])}"
|
20
|
+
end
|
21
|
+
json_response(200, result_hash)
|
22
|
+
end
|
23
|
+
|
24
|
+
def post(request)
|
25
|
+
contents = request.body
|
26
|
+
key = get_key(contents)
|
27
|
+
if key.nil?
|
28
|
+
error(400, "Must specify '#{identity_key}' in JSON")
|
29
|
+
else
|
30
|
+
create_data(request, request.rest_path, key, contents)
|
31
|
+
json_response(201, {'uri' => "#{build_uri(request.base_uri, request.rest_path + [key])}"})
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def get_key(contents)
|
36
|
+
JSON.parse(contents, :create_additions => false)[identity_key]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'json'
|
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_key = 'name')
|
10
|
+
super(server)
|
11
|
+
@identity_key = identity_key
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :identity_key
|
15
|
+
|
16
|
+
def get(request)
|
17
|
+
already_json_response(200, populate_defaults(request, get_data(request)))
|
18
|
+
end
|
19
|
+
|
20
|
+
def put(request)
|
21
|
+
# We grab the old body to trigger a 404 if it doesn't exist
|
22
|
+
old_body = get_data(request)
|
23
|
+
request_json = JSON.parse(request.body, :create_additions => false)
|
24
|
+
key = request_json[identity_key] || request.rest_path[-1]
|
25
|
+
# If it's a rename, check for conflict and delete the old value
|
26
|
+
rename = key != request.rest_path[-1]
|
27
|
+
if rename
|
28
|
+
begin
|
29
|
+
data_store.create(request.rest_path[0..-2], key, request.body)
|
30
|
+
rescue DataStore::DataAlreadyExistsError
|
31
|
+
return error(409, "Cannot rename '#{request.rest_path[-1]}' to '#{key}': '#{key}' already exists")
|
32
|
+
end
|
33
|
+
delete_data(request)
|
34
|
+
else
|
35
|
+
set_data(request, request.rest_path, request.body)
|
36
|
+
end
|
37
|
+
already_json_response(200, populate_defaults(request, request.body))
|
38
|
+
end
|
39
|
+
|
40
|
+
def delete(request)
|
41
|
+
result = get_data(request)
|
42
|
+
delete_data(request)
|
43
|
+
already_json_response(200, populate_defaults(request, result))
|
44
|
+
end
|
45
|
+
|
46
|
+
def patch_request_body(request)
|
47
|
+
existing_value = get_data(request, nil, :nil)
|
48
|
+
if existing_value
|
49
|
+
request_json = JSON.parse(request.body, :create_additions => false)
|
50
|
+
existing_json = JSON.parse(existing_value, :create_additions => false)
|
51
|
+
merged_json = existing_json.merge(request_json)
|
52
|
+
if merged_json.size > request_json.size
|
53
|
+
return JSON.pretty_generate(merged_json)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
request.body
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'chef_zero/endpoints/rest_object_endpoint'
|
3
|
+
require 'chef_zero/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 = JSON.parse(response_json, :create_additions => false)
|
11
|
+
role = DataNormalizer.normalize_role(role, request.rest_path[1])
|
12
|
+
JSON.pretty_generate(role)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'json'
|
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 = JSON.parse(get_data(request, request.rest_path[0..1]), :create_additions => false)
|
10
|
+
json_response(200, [ '_default' ] + (role['env_run_lists'].keys || []))
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'chef_zero/rest_base'
|
2
|
+
require 'chef_zero/rest_error_response'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module ChefZero
|
6
|
+
module Endpoints
|
7
|
+
# /sandboxes/ID
|
8
|
+
class SandboxEndpoint < RestBase
|
9
|
+
def put(request)
|
10
|
+
existing_sandbox = JSON.parse(get_data(request), :create_additions => false)
|
11
|
+
existing_sandbox['checksums'].each do |checksum|
|
12
|
+
if !exists_data?(request, ['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[1],
|
19
|
+
:name => request.rest_path[1],
|
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
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'json'
|
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 = JSON.parse(request.body, :create_additions => false)['checksums']
|
17
|
+
result_checksums = {}
|
18
|
+
needed_checksums.keys.each do |needed_checksum|
|
19
|
+
if list_data(request, ['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, ['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, JSON.pretty_generate({
|
38
|
+
:create_time => time_str,
|
39
|
+
:checksums => sandbox_checksums
|
40
|
+
}))
|
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
|
51
|
+
|