chef-zero 4.2.3 → 4.3.0
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/LICENSE +201 -201
- data/README.md +155 -150
- data/Rakefile +31 -31
- data/bin/chef-zero +100 -100
- data/lib/chef_zero.rb +10 -7
- data/lib/chef_zero/chef_data/acl_path.rb +139 -139
- data/lib/chef_zero/chef_data/cookbook_data.rb +240 -240
- data/lib/chef_zero/chef_data/data_normalizer.rb +207 -207
- data/lib/chef_zero/chef_data/default_creator.rb +446 -446
- data/lib/chef_zero/data_store/data_already_exists_error.rb +29 -29
- data/lib/chef_zero/data_store/data_error.rb +31 -31
- data/lib/chef_zero/data_store/data_not_found_error.rb +28 -28
- data/lib/chef_zero/data_store/default_facade.rb +149 -149
- 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 +155 -155
- data/lib/chef_zero/data_store/raw_file_store.rb +147 -147
- data/lib/chef_zero/data_store/v1_to_v2_adapter.rb +142 -142
- data/lib/chef_zero/data_store/v2_to_v1_adapter.rb +107 -107
- data/lib/chef_zero/endpoints/acl_endpoint.rb +38 -38
- data/lib/chef_zero/endpoints/acls_endpoint.rb +29 -29
- data/lib/chef_zero/endpoints/actor_endpoint.rb +94 -88
- data/lib/chef_zero/endpoints/actors_endpoint.rb +64 -64
- data/lib/chef_zero/endpoints/authenticate_user_endpoint.rb +31 -31
- data/lib/chef_zero/endpoints/container_endpoint.rb +22 -22
- data/lib/chef_zero/endpoints/containers_endpoint.rb +13 -13
- data/lib/chef_zero/endpoints/cookbook_endpoint.rb +39 -39
- data/lib/chef_zero/endpoints/cookbook_version_endpoint.rb +119 -119
- data/lib/chef_zero/endpoints/cookbooks_base.rb +65 -65
- 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/environment_cookbook_endpoint.rb +24 -24
- data/lib/chef_zero/endpoints/environment_cookbook_versions_endpoint.rb +123 -123
- 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 +17 -17
- data/lib/chef_zero/endpoints/node_identifiers_endpoint.rb +22 -0
- 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 -29
- data/lib/chef_zero/endpoints/organization_authenticate_user_endpoint.rb +26 -26
- data/lib/chef_zero/endpoints/organization_endpoint.rb +46 -41
- data/lib/chef_zero/endpoints/organization_user_base.rb +15 -0
- data/lib/chef_zero/endpoints/organization_user_endpoint.rb +26 -48
- data/lib/chef_zero/endpoints/organization_users_endpoint.rb +43 -14
- data/lib/chef_zero/endpoints/organization_validator_key_endpoint.rb +20 -20
- data/lib/chef_zero/endpoints/organizations_endpoint.rb +62 -55
- data/lib/chef_zero/endpoints/policies_endpoint.rb +151 -154
- data/lib/chef_zero/endpoints/principal_endpoint.rb +42 -42
- data/lib/chef_zero/endpoints/rest_list_endpoint.rb +42 -42
- data/lib/chef_zero/endpoints/rest_object_endpoint.rb +63 -63
- 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 +50 -50
- data/lib/chef_zero/endpoints/search_endpoint.rb +194 -192
- data/lib/chef_zero/endpoints/searches_endpoint.rb +18 -18
- data/lib/chef_zero/endpoints/server_api_version_endpoint.rb +14 -0
- data/lib/chef_zero/endpoints/system_recovery_endpoint.rb +30 -30
- data/lib/chef_zero/endpoints/user_association_request_endpoint.rb +40 -40
- 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 +12 -12
- data/lib/chef_zero/log.rb +7 -7
- data/lib/chef_zero/rest_base.rb +242 -214
- data/lib/chef_zero/rest_error_response.rb +11 -11
- data/lib/chef_zero/rest_request.rb +69 -65
- data/lib/chef_zero/rest_router.rb +45 -45
- data/lib/chef_zero/rspec.rb +308 -308
- data/lib/chef_zero/server.rb +642 -637
- data/lib/chef_zero/socketless_server_map.rb +92 -92
- 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 +29 -29
- 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 +43 -43
- data/lib/chef_zero/solr/solr_doc.rb +53 -53
- data/lib/chef_zero/solr/solr_parser.rb +203 -203
- data/lib/chef_zero/version.rb +3 -3
- data/spec/run_oc_pedant.rb +63 -56
- data/spec/search_spec.rb +32 -32
- data/spec/server_spec.rb +92 -91
- data/spec/socketless_server_map_spec.rb +76 -76
- data/spec/support/oc_pedant.rb +132 -134
- data/spec/support/stickywicket.pem +27 -27
- metadata +10 -15
- data/spec/run_pedant.rb +0 -103
- data/spec/support/pedant.rb +0 -129
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
require 'chef_zero/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 'chef_zero/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
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
require 'chef_zero/rest_base'
|
|
2
|
+
|
|
3
|
+
module ChefZero
|
|
4
|
+
module Endpoints
|
|
5
|
+
# /server_api_version
|
|
6
|
+
class ServerAPIVersionEndpoint < RestBase
|
|
7
|
+
API_VERSION = 1
|
|
8
|
+
def get(request)
|
|
9
|
+
json_response(200, {"min_api_version"=>MIN_API_VERSION, "max_api_version"=>MAX_API_VERSION},
|
|
10
|
+
request.api_version, API_VERSION)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
require 'ffi_yajl'
|
|
2
|
-
require 'chef_zero/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, :create_additions => false)
|
|
10
|
-
name = request_json['username']
|
|
11
|
-
password = request_json['password']
|
|
12
|
-
user = get_data(request, request.rest_path[0..-2] + ['users', name], :nil)
|
|
13
|
-
if !user
|
|
14
|
-
raise RestErrorResponse.new(403, "Nonexistent user")
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
user = FFI_Yajl::Parser.parse(user, :create_additions => false)
|
|
18
|
-
user = ChefData::DataNormalizer.normalize_user(user, name, [ 'username' ], server.options[:osc_compat])
|
|
19
|
-
if !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'
|
|
2
|
+
require 'chef_zero/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, :create_additions => false)
|
|
10
|
+
name = request_json['username']
|
|
11
|
+
password = request_json['password']
|
|
12
|
+
user = get_data(request, request.rest_path[0..-2] + ['users', name], :nil)
|
|
13
|
+
if !user
|
|
14
|
+
raise RestErrorResponse.new(403, "Nonexistent user")
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
user = FFI_Yajl::Parser.parse(user, :create_additions => false)
|
|
18
|
+
user = ChefData::DataNormalizer.normalize_user(user, name, [ 'username' ], server.options[:osc_compat])
|
|
19
|
+
if !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,40 +1,40 @@
|
|
|
1
|
-
require 'ffi_yajl'
|
|
2
|
-
require 'chef_zero/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
|
-
orgname = $1
|
|
15
|
-
|
|
16
|
-
json = FFI_Yajl::Parser.parse(request.body, :create_additions => false)
|
|
17
|
-
association_request_path = [ 'organizations', orgname, 'association_requests', username ]
|
|
18
|
-
if json['response'] == 'accept'
|
|
19
|
-
users = get_data(request, [ 'organizations', orgname, 'groups', 'users' ])
|
|
20
|
-
users = FFI_Yajl::Parser.parse(users, :create_additions => false)
|
|
21
|
-
|
|
22
|
-
delete_data(request, association_request_path)
|
|
23
|
-
create_data(request, [ 'organizations', orgname, 'users' ], username, '{}')
|
|
24
|
-
|
|
25
|
-
# Add the user to the users group if it isn't already there
|
|
26
|
-
if !users['users'] || !users['users'].include?(username)
|
|
27
|
-
users['users'] ||= []
|
|
28
|
-
users['users'] |= [ username ]
|
|
29
|
-
set_data(request, [ 'organizations', orgname, 'groups', 'users' ], FFI_Yajl::Encoder.encode(users, :pretty => true))
|
|
30
|
-
end
|
|
31
|
-
elsif json['response'] == 'reject'
|
|
32
|
-
delete_data(request, association_request_path)
|
|
33
|
-
else
|
|
34
|
-
raise RestErrorResponse.new(400, "response parameter was missing or set to the wrong value (must be accept or reject)")
|
|
35
|
-
end
|
|
36
|
-
json_response(200, { 'organization' => { 'name' => orgname } })
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
end
|
|
1
|
+
require 'ffi_yajl'
|
|
2
|
+
require 'chef_zero/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
|
+
orgname = $1
|
|
15
|
+
|
|
16
|
+
json = FFI_Yajl::Parser.parse(request.body, :create_additions => false)
|
|
17
|
+
association_request_path = [ 'organizations', orgname, 'association_requests', username ]
|
|
18
|
+
if json['response'] == 'accept'
|
|
19
|
+
users = get_data(request, [ 'organizations', orgname, 'groups', 'users' ])
|
|
20
|
+
users = FFI_Yajl::Parser.parse(users, :create_additions => false)
|
|
21
|
+
|
|
22
|
+
delete_data(request, association_request_path)
|
|
23
|
+
create_data(request, [ 'organizations', orgname, 'users' ], username, '{}')
|
|
24
|
+
|
|
25
|
+
# Add the user to the users group if it isn't already there
|
|
26
|
+
if !users['users'] || !users['users'].include?(username)
|
|
27
|
+
users['users'] ||= []
|
|
28
|
+
users['users'] |= [ username ]
|
|
29
|
+
set_data(request, [ 'organizations', orgname, 'groups', 'users' ], FFI_Yajl::Encoder.encode(users, :pretty => true))
|
|
30
|
+
end
|
|
31
|
+
elsif json['response'] == 'reject'
|
|
32
|
+
delete_data(request, association_request_path)
|
|
33
|
+
else
|
|
34
|
+
raise RestErrorResponse.new(400, "response parameter was missing or set to the wrong value (must be accept or reject)")
|
|
35
|
+
end
|
|
36
|
+
json_response(200, { 'organization' => { 'name' => orgname } })
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
require 'ffi_yajl'
|
|
2
|
-
require 'chef_zero/rest_base'
|
|
3
|
-
|
|
4
|
-
module ChefZero
|
|
5
|
-
module Endpoints
|
|
6
|
-
# /users/NAME/association_requests/count
|
|
7
|
-
class UserAssociationRequestsCountEndpoint < RestBase
|
|
8
|
-
def get(request)
|
|
9
|
-
get_data(request, request.rest_path[0..-3])
|
|
10
|
-
|
|
11
|
-
username = request.rest_path[1]
|
|
12
|
-
result = list_data(request, [ 'organizations' ]).select do |org|
|
|
13
|
-
exists_data?(request, [ 'organizations', org, 'association_requests', username ])
|
|
14
|
-
end
|
|
15
|
-
json_response(200, { "value" => result.size })
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
1
|
+
require 'ffi_yajl'
|
|
2
|
+
require 'chef_zero/rest_base'
|
|
3
|
+
|
|
4
|
+
module ChefZero
|
|
5
|
+
module Endpoints
|
|
6
|
+
# /users/NAME/association_requests/count
|
|
7
|
+
class UserAssociationRequestsCountEndpoint < RestBase
|
|
8
|
+
def get(request)
|
|
9
|
+
get_data(request, request.rest_path[0..-3])
|
|
10
|
+
|
|
11
|
+
username = request.rest_path[1]
|
|
12
|
+
result = list_data(request, [ 'organizations' ]).select do |org|
|
|
13
|
+
exists_data?(request, [ 'organizations', org, 'association_requests', username ])
|
|
14
|
+
end
|
|
15
|
+
json_response(200, { "value" => result.size })
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
require 'ffi_yajl'
|
|
2
|
-
require 'chef_zero/rest_base'
|
|
3
|
-
|
|
4
|
-
module ChefZero
|
|
5
|
-
module Endpoints
|
|
6
|
-
# /users/USER/association_requests
|
|
7
|
-
class UserAssociationRequestsEndpoint < RestBase
|
|
8
|
-
def get(request)
|
|
9
|
-
get_data(request, request.rest_path[0..-2])
|
|
10
|
-
username = request.rest_path[1]
|
|
11
|
-
result = list_data(request, [ 'organizations' ]).select do |org|
|
|
12
|
-
exists_data?(request, [ 'organizations', org, 'association_requests', username ])
|
|
13
|
-
end
|
|
14
|
-
result = result.map { |org| { "id" => "#{username}-#{org}", "orgname" => org } }
|
|
15
|
-
json_response(200, result)
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
1
|
+
require 'ffi_yajl'
|
|
2
|
+
require 'chef_zero/rest_base'
|
|
3
|
+
|
|
4
|
+
module ChefZero
|
|
5
|
+
module Endpoints
|
|
6
|
+
# /users/USER/association_requests
|
|
7
|
+
class UserAssociationRequestsEndpoint < RestBase
|
|
8
|
+
def get(request)
|
|
9
|
+
get_data(request, request.rest_path[0..-2])
|
|
10
|
+
username = request.rest_path[1]
|
|
11
|
+
result = list_data(request, [ 'organizations' ]).select do |org|
|
|
12
|
+
exists_data?(request, [ 'organizations', org, 'association_requests', username ])
|
|
13
|
+
end
|
|
14
|
+
result = result.map { |org| { "id" => "#{username}-#{org}", "orgname" => org } }
|
|
15
|
+
json_response(200, result)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
require 'ffi_yajl'
|
|
2
|
-
require 'chef_zero/rest_base'
|
|
3
|
-
|
|
4
|
-
module ChefZero
|
|
5
|
-
module Endpoints
|
|
6
|
-
# /users/USER/organizations
|
|
7
|
-
class UserOrganizationsEndpoint < RestBase
|
|
8
|
-
def get(request)
|
|
9
|
-
username = request.rest_path[1]
|
|
10
|
-
result = list_data(request, [ 'organizations' ]).select do |orgname|
|
|
11
|
-
exists_data?(request, [ 'organizations', orgname, 'users', username ])
|
|
12
|
-
end
|
|
13
|
-
result = result.map do |orgname|
|
|
14
|
-
org = get_data(request, [ 'organizations', orgname, 'org' ])
|
|
15
|
-
org = FFI_Yajl::Parser.parse(org, :create_additions => false)
|
|
16
|
-
ChefData::DataNormalizer.normalize_organization(org, orgname)
|
|
17
|
-
end
|
|
18
|
-
json_response(200, result)
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
end
|
|
1
|
+
require 'ffi_yajl'
|
|
2
|
+
require 'chef_zero/rest_base'
|
|
3
|
+
|
|
4
|
+
module ChefZero
|
|
5
|
+
module Endpoints
|
|
6
|
+
# /users/USER/organizations
|
|
7
|
+
class UserOrganizationsEndpoint < RestBase
|
|
8
|
+
def get(request)
|
|
9
|
+
username = request.rest_path[1]
|
|
10
|
+
result = list_data(request, [ 'organizations' ]).select do |orgname|
|
|
11
|
+
exists_data?(request, [ 'organizations', orgname, 'users', username ])
|
|
12
|
+
end
|
|
13
|
+
result = result.map do |orgname|
|
|
14
|
+
org = get_data(request, [ 'organizations', orgname, 'org' ])
|
|
15
|
+
org = FFI_Yajl::Parser.parse(org, :create_additions => false)
|
|
16
|
+
{ "organization" => ChefData::DataNormalizer.normalize_organization(org, orgname) }
|
|
17
|
+
end
|
|
18
|
+
json_response(200, result)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
require 'chef_zero/rest_base'
|
|
2
|
-
|
|
3
|
-
module ChefZero
|
|
4
|
-
module Endpoints
|
|
5
|
-
# /version
|
|
6
|
-
class VersionEndpoint < RestBase
|
|
7
|
-
def get(request)
|
|
8
|
-
text_response(200, "chef-zero #{ChefZero::VERSION}\n")
|
|
9
|
-
end
|
|
10
|
-
end
|
|
11
|
-
end
|
|
12
|
-
end
|
|
1
|
+
require 'chef_zero/rest_base'
|
|
2
|
+
|
|
3
|
+
module ChefZero
|
|
4
|
+
module Endpoints
|
|
5
|
+
# /version
|
|
6
|
+
class VersionEndpoint < RestBase
|
|
7
|
+
def get(request)
|
|
8
|
+
text_response(200, "chef-zero #{ChefZero::VERSION}\n")
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
data/lib/chef_zero/log.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
require 'mixlib/log'
|
|
2
|
-
|
|
3
|
-
module ChefZero
|
|
4
|
-
class Log
|
|
5
|
-
extend Mixlib::Log
|
|
6
|
-
end
|
|
7
|
-
end
|
|
1
|
+
require 'mixlib/log'
|
|
2
|
+
|
|
3
|
+
module ChefZero
|
|
4
|
+
class Log
|
|
5
|
+
extend Mixlib::Log
|
|
6
|
+
end
|
|
7
|
+
end
|
data/lib/chef_zero/rest_base.rb
CHANGED
|
@@ -1,214 +1,242 @@
|
|
|
1
|
-
require 'chef_zero/rest_request'
|
|
2
|
-
require 'chef_zero/rest_error_response'
|
|
3
|
-
require 'chef_zero/data_store/data_not_found_error'
|
|
4
|
-
require 'chef_zero/chef_data/acl_path'
|
|
5
|
-
|
|
6
|
-
module ChefZero
|
|
7
|
-
class RestBase
|
|
8
|
-
def initialize(server)
|
|
9
|
-
@server = server
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
attr_reader :server
|
|
13
|
-
|
|
14
|
-
def data_store
|
|
15
|
-
server.data_store
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def
|
|
19
|
-
|
|
20
|
-
if
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
return
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
begin
|
|
52
|
-
|
|
53
|
-
rescue
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
begin
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
end
|
|
187
|
-
|
|
188
|
-
def
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
def
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
end
|
|
205
|
-
|
|
206
|
-
def
|
|
207
|
-
"
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
def
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
1
|
+
require 'chef_zero/rest_request'
|
|
2
|
+
require 'chef_zero/rest_error_response'
|
|
3
|
+
require 'chef_zero/data_store/data_not_found_error'
|
|
4
|
+
require 'chef_zero/chef_data/acl_path'
|
|
5
|
+
|
|
6
|
+
module ChefZero
|
|
7
|
+
class RestBase
|
|
8
|
+
def initialize(server)
|
|
9
|
+
@server = server
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
attr_reader :server
|
|
13
|
+
|
|
14
|
+
def data_store
|
|
15
|
+
server.data_store
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def check_api_version(request)
|
|
19
|
+
version = request.api_version
|
|
20
|
+
return nil if version.nil? # Not present in headers
|
|
21
|
+
|
|
22
|
+
if version.to_i.to_s != version.to_s # Version is not an Integer
|
|
23
|
+
return json_response(406, { "username" => request.requestor }, -1, -1)
|
|
24
|
+
elsif version.to_i > MAX_API_VERSION or version.to_i < MIN_API_VERSION
|
|
25
|
+
response = {
|
|
26
|
+
"error" => "invalid-x-ops-server-api-version",
|
|
27
|
+
"message" => "Specified version #{version} not supported",
|
|
28
|
+
"min_api_version" => MIN_API_VERSION,
|
|
29
|
+
"max_api_version" => MAX_API_VERSION
|
|
30
|
+
}
|
|
31
|
+
return json_response(406, response, version, -1)
|
|
32
|
+
else
|
|
33
|
+
return nil
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def call(request)
|
|
38
|
+
response = check_api_version(request)
|
|
39
|
+
return response unless response.nil?
|
|
40
|
+
|
|
41
|
+
method = request.method.downcase.to_sym
|
|
42
|
+
if !self.respond_to?(method)
|
|
43
|
+
accept_methods = [:get, :put, :post, :delete].select { |m| self.respond_to?(m) }
|
|
44
|
+
accept_methods_str = accept_methods.map { |m| m.to_s.upcase }.join(', ')
|
|
45
|
+
return [405, {"Content-Type" => "text/plain", "Allow" => accept_methods_str}, "Bad request method for '#{request.env['REQUEST_PATH']}': #{request.env['REQUEST_METHOD']}"]
|
|
46
|
+
end
|
|
47
|
+
if json_only && !accepts?(request, 'application', 'json')
|
|
48
|
+
return [406, {"Content-Type" => "text/plain"}, "Must accept application/json"]
|
|
49
|
+
end
|
|
50
|
+
# Dispatch to get()/post()/put()/delete()
|
|
51
|
+
begin
|
|
52
|
+
self.send(method, request)
|
|
53
|
+
rescue RestErrorResponse => e
|
|
54
|
+
ChefZero::Log.debug("#{e.inspect}\n#{e.backtrace.join("\n")}")
|
|
55
|
+
error(e.response_code, e.error)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def json_only
|
|
60
|
+
true
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def accepts?(request, category, type)
|
|
64
|
+
# If HTTP_ACCEPT is not sent at all, assume it accepts anything
|
|
65
|
+
# This parses as per http://tools.ietf.org/html/rfc7231#section-5.3
|
|
66
|
+
return true if !request.env['HTTP_ACCEPT']
|
|
67
|
+
accepts = request.env['HTTP_ACCEPT'].split(/,\s*/).map { |x| x.split(';',2)[0].strip }
|
|
68
|
+
return accepts.include?("#{category}/#{type}") || accepts.include?("#{category}/*") || accepts.include?('*/*')
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def get_data(request, rest_path=nil, *options)
|
|
72
|
+
rest_path ||= request.rest_path
|
|
73
|
+
begin
|
|
74
|
+
data_store.get(rest_path, request)
|
|
75
|
+
rescue DataStore::DataNotFoundError
|
|
76
|
+
if options.include?(:nil)
|
|
77
|
+
nil
|
|
78
|
+
elsif options.include?(:data_store_exceptions)
|
|
79
|
+
raise
|
|
80
|
+
else
|
|
81
|
+
raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, rest_path)}")
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def list_data(request, rest_path=nil, *options)
|
|
87
|
+
rest_path ||= request.rest_path
|
|
88
|
+
begin
|
|
89
|
+
data_store.list(rest_path)
|
|
90
|
+
rescue DataStore::DataNotFoundError
|
|
91
|
+
if options.include?(:data_store_exceptions)
|
|
92
|
+
raise
|
|
93
|
+
else
|
|
94
|
+
raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, rest_path)}")
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def delete_data(request, rest_path=nil, *options)
|
|
100
|
+
rest_path ||= request.rest_path
|
|
101
|
+
begin
|
|
102
|
+
data_store.delete(rest_path, *options)
|
|
103
|
+
rescue DataStore::DataNotFoundError
|
|
104
|
+
if options.include?(:data_store_exceptions)
|
|
105
|
+
raise
|
|
106
|
+
else
|
|
107
|
+
raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, request.rest_path)}")
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
begin
|
|
112
|
+
acl_path = ChefData::AclPath.get_acl_data_path(rest_path)
|
|
113
|
+
data_store.delete(acl_path) if acl_path
|
|
114
|
+
rescue DataStore::DataNotFoundError
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def delete_data_dir(request, rest_path, *options)
|
|
119
|
+
rest_path ||= request.rest_path
|
|
120
|
+
begin
|
|
121
|
+
data_store.delete_dir(rest_path, *options)
|
|
122
|
+
rescue DataStore::DataNotFoundError
|
|
123
|
+
if options.include?(:data_store_exceptions)
|
|
124
|
+
raise
|
|
125
|
+
else
|
|
126
|
+
raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, request.rest_path)}")
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
begin
|
|
131
|
+
acl_path = ChefData::AclPath.get_acl_data_path(rest_path)
|
|
132
|
+
data_store.delete(acl_path) if acl_path
|
|
133
|
+
rescue DataStore::DataNotFoundError
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def set_data(request, rest_path, data, *options)
|
|
138
|
+
rest_path ||= request.rest_path
|
|
139
|
+
begin
|
|
140
|
+
data_store.set(rest_path, data, *options, :requestor => request.requestor)
|
|
141
|
+
rescue DataStore::DataNotFoundError
|
|
142
|
+
if options.include?(:data_store_exceptions)
|
|
143
|
+
raise
|
|
144
|
+
else
|
|
145
|
+
raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, request.rest_path)}")
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def create_data_dir(request, rest_path, name, *options)
|
|
151
|
+
rest_path ||= request.rest_path
|
|
152
|
+
begin
|
|
153
|
+
data_store.create_dir(rest_path, name, *options, :requestor => request.requestor)
|
|
154
|
+
rescue DataStore::DataNotFoundError
|
|
155
|
+
if options.include?(:data_store_exceptions)
|
|
156
|
+
raise
|
|
157
|
+
else
|
|
158
|
+
raise RestErrorResponse.new(404, "Parent not found: #{build_uri(request.base_uri, request.rest_path)}")
|
|
159
|
+
end
|
|
160
|
+
rescue DataStore::DataAlreadyExistsError
|
|
161
|
+
if options.include?(:data_store_exceptions)
|
|
162
|
+
raise
|
|
163
|
+
else
|
|
164
|
+
raise RestErrorResponse.new(409, "Object already exists: #{build_uri(request.base_uri, request.rest_path + [name])}")
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def create_data(request, rest_path, name, data, *options)
|
|
170
|
+
rest_path ||= request.rest_path
|
|
171
|
+
begin
|
|
172
|
+
data_store.create(rest_path, name, data, *options, :requestor => request.requestor)
|
|
173
|
+
rescue DataStore::DataNotFoundError
|
|
174
|
+
if options.include?(:data_store_exceptions)
|
|
175
|
+
raise
|
|
176
|
+
else
|
|
177
|
+
raise RestErrorResponse.new(404, "Parent not found: #{build_uri(request.base_uri, request.rest_path)}")
|
|
178
|
+
end
|
|
179
|
+
rescue DataStore::DataAlreadyExistsError
|
|
180
|
+
if options.include?(:data_store_exceptions)
|
|
181
|
+
raise
|
|
182
|
+
else
|
|
183
|
+
raise RestErrorResponse.new(409, "Object already exists: #{build_uri(request.base_uri, request.rest_path + [name])}")
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def exists_data?(request, rest_path=nil)
|
|
189
|
+
rest_path ||= request.rest_path
|
|
190
|
+
data_store.exists?(rest_path)
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def exists_data_dir?(request, rest_path=nil)
|
|
194
|
+
rest_path ||= request.rest_path
|
|
195
|
+
data_store.exists_dir?(rest_path)
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def error(response_code, error)
|
|
199
|
+
json_response(response_code, {"error" => [error]})
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def json_response(response_code, json, request_version=0, response_version=0)
|
|
203
|
+
already_json_response(response_code, FFI_Yajl::Encoder.encode(json, :pretty => true), request_version, response_version)
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def text_response(response_code, text)
|
|
207
|
+
[response_code, {"Content-Type" => "text/plain"}, text]
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def already_json_response(response_code, json_text, request_version=0, response_version=0)
|
|
211
|
+
header = { "min_version" => MIN_API_VERSION.to_s, "max_version" => MAX_API_VERSION.to_s,
|
|
212
|
+
"request_version" => request_version.to_s,
|
|
213
|
+
"response_version" => response_version.to_s }
|
|
214
|
+
[ response_code,
|
|
215
|
+
{ "Content-Type" => "application/json",
|
|
216
|
+
"X-Ops-Server-API-Version" => FFI_Yajl::Encoder.encode(header) },
|
|
217
|
+
json_text ]
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
# To be called from inside rest endpoints
|
|
221
|
+
def build_uri(base_uri, rest_path)
|
|
222
|
+
if server.options[:single_org]
|
|
223
|
+
# Strip off /organizations/chef if we are in single org mode
|
|
224
|
+
if rest_path[0..1] != [ 'organizations', server.options[:single_org] ]
|
|
225
|
+
raise "Unexpected URL #{rest_path[0..1]} passed to build_uri in single org mode"
|
|
226
|
+
else
|
|
227
|
+
"#{base_uri}/#{rest_path[2..-1].join('/')}"
|
|
228
|
+
end
|
|
229
|
+
else
|
|
230
|
+
"#{base_uri}/#{rest_path.join('/')}"
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def self.build_uri(base_uri, rest_path)
|
|
235
|
+
"#{base_uri}/#{rest_path.join('/')}"
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def populate_defaults(request, response)
|
|
239
|
+
response
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
end
|