chef-zero 4.3.0 → 4.3.1
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 -155
- data/Rakefile +31 -31
- data/bin/chef-zero +100 -100
- data/lib/chef_zero.rb +10 -10
- 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 +208 -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 -94
- 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 -22
- 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 +46 -46
- data/lib/chef_zero/endpoints/organization_user_base.rb +15 -15
- data/lib/chef_zero/endpoints/organization_user_endpoint.rb +26 -26
- 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 +62 -62
- data/lib/chef_zero/endpoints/policies_endpoint.rb +151 -151
- 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 -194
- 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/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 -242
- data/lib/chef_zero/rest_error_response.rb +11 -11
- data/lib/chef_zero/rest_request.rb +69 -69
- data/lib/chef_zero/rest_router.rb +45 -45
- data/lib/chef_zero/rspec.rb +308 -308
- data/lib/chef_zero/server.rb +642 -642
- 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 -63
- data/spec/search_spec.rb +32 -32
- data/spec/server_spec.rb +92 -92
- data/spec/socketless_server_map_spec.rb +76 -76
- data/spec/support/oc_pedant.rb +132 -132
- data/spec/support/stickywicket.pem +27 -27
- metadata +3 -3
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
require 'ffi_yajl'
|
|
2
|
-
require 'chef_zero/rest_base'
|
|
3
|
-
require 'uuidtools'
|
|
4
|
-
|
|
5
|
-
module ChefZero
|
|
6
|
-
module Endpoints
|
|
7
|
-
# /organizations/NAME/_validator_key
|
|
8
|
-
class OrganizationValidatorKeyEndpoint < RestBase
|
|
9
|
-
def post(request)
|
|
10
|
-
org_name = request.rest_path[-2]
|
|
11
|
-
validator_path = [ 'organizations', org_name, 'clients', "#{org_name}-validator"]
|
|
12
|
-
validator = FFI_Yajl::Parser.parse(get_data(request, validator_path), :create_additions => false)
|
|
13
|
-
private_key, public_key = server.gen_key_pair
|
|
14
|
-
validator['public_key'] = public_key
|
|
15
|
-
set_data(request, validator_path, FFI_Yajl::Encoder.encode(validator, :pretty => true))
|
|
16
|
-
json_response(200, { 'private_key' => private_key })
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
|
1
|
+
require 'ffi_yajl'
|
|
2
|
+
require 'chef_zero/rest_base'
|
|
3
|
+
require 'uuidtools'
|
|
4
|
+
|
|
5
|
+
module ChefZero
|
|
6
|
+
module Endpoints
|
|
7
|
+
# /organizations/NAME/_validator_key
|
|
8
|
+
class OrganizationValidatorKeyEndpoint < RestBase
|
|
9
|
+
def post(request)
|
|
10
|
+
org_name = request.rest_path[-2]
|
|
11
|
+
validator_path = [ 'organizations', org_name, 'clients', "#{org_name}-validator"]
|
|
12
|
+
validator = FFI_Yajl::Parser.parse(get_data(request, validator_path), :create_additions => false)
|
|
13
|
+
private_key, public_key = server.gen_key_pair
|
|
14
|
+
validator['public_key'] = public_key
|
|
15
|
+
set_data(request, validator_path, FFI_Yajl::Encoder.encode(validator, :pretty => true))
|
|
16
|
+
json_response(200, { 'private_key' => private_key })
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -1,62 +1,62 @@
|
|
|
1
|
-
require 'ffi_yajl'
|
|
2
|
-
require 'chef_zero/rest_base'
|
|
3
|
-
require 'uuidtools'
|
|
4
|
-
|
|
5
|
-
module ChefZero
|
|
6
|
-
module Endpoints
|
|
7
|
-
# /organizations
|
|
8
|
-
class OrganizationsEndpoint < RestBase
|
|
9
|
-
def get(request)
|
|
10
|
-
result = {}
|
|
11
|
-
data_store.list(request.rest_path).each do |name|
|
|
12
|
-
result[name] = build_uri(request.base_uri, request.rest_path + [name])
|
|
13
|
-
end
|
|
14
|
-
json_response(200, result)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def post(request)
|
|
18
|
-
contents = FFI_Yajl::Parser.parse(request.body, :create_additions => false)
|
|
19
|
-
name = contents['name']
|
|
20
|
-
full_name = contents['full_name']
|
|
21
|
-
if name.nil?
|
|
22
|
-
error(400, "Must specify 'name' in JSON")
|
|
23
|
-
elsif full_name.nil?
|
|
24
|
-
error(400, "Must specify 'full_name' in JSON")
|
|
25
|
-
elsif exists_data_dir?(request, request.rest_path + [ name ])
|
|
26
|
-
error(409, "Organization already exists")
|
|
27
|
-
else
|
|
28
|
-
create_data_dir(request, request.rest_path, name, :requestor => request.requestor)
|
|
29
|
-
|
|
30
|
-
org = {
|
|
31
|
-
"guid" => UUIDTools::UUID.random_create.to_s.gsub('-', ''),
|
|
32
|
-
"assigned_at" => Time.now.to_s
|
|
33
|
-
}.merge(contents)
|
|
34
|
-
org_path = request.rest_path + [ name ]
|
|
35
|
-
set_data(request, org_path + [ 'org' ], FFI_Yajl::Encoder.encode(org, :pretty => true))
|
|
36
|
-
|
|
37
|
-
if server.generate_real_keys?
|
|
38
|
-
# Create the validator client
|
|
39
|
-
validator_name = "#{name}-validator"
|
|
40
|
-
validator_path = org_path + [ 'clients', validator_name ]
|
|
41
|
-
private_key, public_key = server.gen_key_pair
|
|
42
|
-
validator = FFI_Yajl::Encoder.encode({
|
|
43
|
-
'validator' => true,
|
|
44
|
-
'public_key' => public_key
|
|
45
|
-
}, :pretty => true)
|
|
46
|
-
set_data(request, validator_path, validator)
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
json_response(201, {
|
|
51
|
-
"uri" => "#{build_uri(request.base_uri, org_path)}",
|
|
52
|
-
"name" => name,
|
|
53
|
-
"org_type" => org["org_type"],
|
|
54
|
-
"full_name" => full_name,
|
|
55
|
-
"clientname" => validator_name,
|
|
56
|
-
"private_key" => private_key
|
|
57
|
-
})
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
end
|
|
1
|
+
require 'ffi_yajl'
|
|
2
|
+
require 'chef_zero/rest_base'
|
|
3
|
+
require 'uuidtools'
|
|
4
|
+
|
|
5
|
+
module ChefZero
|
|
6
|
+
module Endpoints
|
|
7
|
+
# /organizations
|
|
8
|
+
class OrganizationsEndpoint < RestBase
|
|
9
|
+
def get(request)
|
|
10
|
+
result = {}
|
|
11
|
+
data_store.list(request.rest_path).each do |name|
|
|
12
|
+
result[name] = build_uri(request.base_uri, request.rest_path + [name])
|
|
13
|
+
end
|
|
14
|
+
json_response(200, result)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def post(request)
|
|
18
|
+
contents = FFI_Yajl::Parser.parse(request.body, :create_additions => false)
|
|
19
|
+
name = contents['name']
|
|
20
|
+
full_name = contents['full_name']
|
|
21
|
+
if name.nil?
|
|
22
|
+
error(400, "Must specify 'name' in JSON")
|
|
23
|
+
elsif full_name.nil?
|
|
24
|
+
error(400, "Must specify 'full_name' in JSON")
|
|
25
|
+
elsif exists_data_dir?(request, request.rest_path + [ name ])
|
|
26
|
+
error(409, "Organization already exists")
|
|
27
|
+
else
|
|
28
|
+
create_data_dir(request, request.rest_path, name, :requestor => request.requestor)
|
|
29
|
+
|
|
30
|
+
org = {
|
|
31
|
+
"guid" => UUIDTools::UUID.random_create.to_s.gsub('-', ''),
|
|
32
|
+
"assigned_at" => Time.now.to_s
|
|
33
|
+
}.merge(contents)
|
|
34
|
+
org_path = request.rest_path + [ name ]
|
|
35
|
+
set_data(request, org_path + [ 'org' ], FFI_Yajl::Encoder.encode(org, :pretty => true))
|
|
36
|
+
|
|
37
|
+
if server.generate_real_keys?
|
|
38
|
+
# Create the validator client
|
|
39
|
+
validator_name = "#{name}-validator"
|
|
40
|
+
validator_path = org_path + [ 'clients', validator_name ]
|
|
41
|
+
private_key, public_key = server.gen_key_pair
|
|
42
|
+
validator = FFI_Yajl::Encoder.encode({
|
|
43
|
+
'validator' => true,
|
|
44
|
+
'public_key' => public_key
|
|
45
|
+
}, :pretty => true)
|
|
46
|
+
set_data(request, validator_path, validator)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
json_response(201, {
|
|
51
|
+
"uri" => "#{build_uri(request.base_uri, org_path)}",
|
|
52
|
+
"name" => name,
|
|
53
|
+
"org_type" => org["org_type"],
|
|
54
|
+
"full_name" => full_name,
|
|
55
|
+
"clientname" => validator_name,
|
|
56
|
+
"private_key" => private_key
|
|
57
|
+
})
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -1,151 +1,151 @@
|
|
|
1
|
-
require 'ffi_yajl'
|
|
2
|
-
|
|
3
|
-
require 'chef_zero/endpoints/rest_object_endpoint'
|
|
4
|
-
require 'chef_zero/chef_data/data_normalizer'
|
|
5
|
-
|
|
6
|
-
module ChefZero
|
|
7
|
-
module Endpoints
|
|
8
|
-
# /policies/:group/:name
|
|
9
|
-
class PoliciesEndpoint < RestObjectEndpoint
|
|
10
|
-
def initialize(server)
|
|
11
|
-
super(server, 'id')
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def get(request)
|
|
15
|
-
already_json_response(200, get_data(request))
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
# Right now we're allowing PUT to create.
|
|
19
|
-
def put(request)
|
|
20
|
-
error = validate(request)
|
|
21
|
-
return error if error
|
|
22
|
-
|
|
23
|
-
code =
|
|
24
|
-
if data_store.exists?(request.rest_path)
|
|
25
|
-
set_data(request, request.rest_path, request.body, :data_store_exceptions)
|
|
26
|
-
200
|
|
27
|
-
else
|
|
28
|
-
name = request.rest_path[4]
|
|
29
|
-
data_store.create(request.rest_path[0..3], name, request.body, :create_dir)
|
|
30
|
-
201
|
|
31
|
-
end
|
|
32
|
-
already_json_response(code, request.body)
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def delete(request)
|
|
36
|
-
result = get_data(request, request.rest_path)
|
|
37
|
-
delete_data(request, request.rest_path, :data_store_exceptions)
|
|
38
|
-
already_json_response(200, result)
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
private
|
|
42
|
-
|
|
43
|
-
def validate(request)
|
|
44
|
-
req_object = validate_json(request.body)
|
|
45
|
-
validate_revision_id(request, req_object) ||
|
|
46
|
-
validate_name(request, req_object) ||
|
|
47
|
-
validate_run_list(req_object) ||
|
|
48
|
-
validate_each_run_list_item(req_object) ||
|
|
49
|
-
validate_cookbook_locks_collection(req_object) ||
|
|
50
|
-
validate_each_cookbook_locks_item(req_object)
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def validate_json(request_body)
|
|
54
|
-
FFI_Yajl::Parser.parse(request_body)
|
|
55
|
-
# TODO: rescue parse error, return 400
|
|
56
|
-
# error(400, "Must specify #{identity_keys.map { |k| k.inspect }.join(' or ')} in JSON")
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def validate_revision_id(request, req_object)
|
|
60
|
-
if !req_object.key?("revision_id")
|
|
61
|
-
error(400, "Field 'revision_id' missing")
|
|
62
|
-
elsif req_object["revision_id"].empty?
|
|
63
|
-
error(400, "Field 'revision_id' invalid")
|
|
64
|
-
elsif req_object["revision_id"].size > 255
|
|
65
|
-
error(400, "Field 'revision_id' invalid")
|
|
66
|
-
elsif req_object["revision_id"] !~ /^[\-[:alnum:]_\.\:]+$/
|
|
67
|
-
error(400, "Field 'revision_id' invalid")
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def validate_name(request, req_object)
|
|
72
|
-
if !req_object.key?("name")
|
|
73
|
-
error(400, "Field 'name' missing")
|
|
74
|
-
elsif req_object["name"] != (uri_policy_name = URI.decode(request.rest_path[4]))
|
|
75
|
-
error(400, "Field 'name' invalid : #{uri_policy_name} does not match #{req_object["name"]}")
|
|
76
|
-
elsif req_object["name"].size > 255
|
|
77
|
-
error(400, "Field 'name' invalid")
|
|
78
|
-
elsif req_object["name"] !~ /^[\-[:alnum:]_\.\:]+$/
|
|
79
|
-
error(400, "Field 'name' invalid")
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def validate_run_list(req_object)
|
|
84
|
-
if !req_object.key?("run_list")
|
|
85
|
-
error(400, "Field 'run_list' missing")
|
|
86
|
-
elsif !req_object["run_list"].kind_of?(Array)
|
|
87
|
-
error(400, "Field 'run_list' is not a valid run list")
|
|
88
|
-
end
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
def validate_each_run_list_item(req_object)
|
|
92
|
-
req_object["run_list"].each do |run_list_item|
|
|
93
|
-
if res_400 = validate_run_list_item(run_list_item)
|
|
94
|
-
return res_400
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
nil
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
def validate_run_list_item(run_list_item)
|
|
101
|
-
if !run_list_item.kind_of?(String)
|
|
102
|
-
error(400, "Field 'run_list' is not a valid run list")
|
|
103
|
-
elsif run_list_item !~ /\Arecipe\[[^\s]+::[^\s]+\]\Z/
|
|
104
|
-
error(400, "Field 'run_list' is not a valid run list")
|
|
105
|
-
end
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
def validate_cookbook_locks_collection(req_object)
|
|
109
|
-
if !req_object.key?("cookbook_locks")
|
|
110
|
-
error(400, "Field 'cookbook_locks' missing")
|
|
111
|
-
elsif !req_object["cookbook_locks"].kind_of?(Hash)
|
|
112
|
-
error(400, "Field 'cookbook_locks' invalid")
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
def validate_each_cookbook_locks_item(req_object)
|
|
117
|
-
req_object["cookbook_locks"].each do |cookbook_name, lock|
|
|
118
|
-
if res_400 = validate_cookbook_locks_item(cookbook_name, lock)
|
|
119
|
-
return res_400
|
|
120
|
-
end
|
|
121
|
-
end
|
|
122
|
-
nil
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
def validate_cookbook_locks_item(cookbook_name, lock)
|
|
126
|
-
if !lock.kind_of?(Hash)
|
|
127
|
-
error(400, "cookbook_lock entries must be a JSON object")
|
|
128
|
-
elsif !lock.key?("identifier")
|
|
129
|
-
error(400, "Field 'identifier' missing")
|
|
130
|
-
elsif lock["identifier"].size > 255
|
|
131
|
-
error(400, "Field 'identifier' invalid")
|
|
132
|
-
elsif !lock.key?("version")
|
|
133
|
-
error(400, "Field 'version' missing")
|
|
134
|
-
elsif lock.key?("dotted_decimal_identifier")
|
|
135
|
-
unless valid_version?(lock["dotted_decimal_identifier"])
|
|
136
|
-
error(400, "Field 'dotted_decimal_identifier' is not a valid version")
|
|
137
|
-
end
|
|
138
|
-
end
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
def valid_version?(version_string)
|
|
142
|
-
Gem::Version.new(version_string)
|
|
143
|
-
true
|
|
144
|
-
rescue ArgumentError
|
|
145
|
-
false
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
end
|
|
149
|
-
end
|
|
150
|
-
end
|
|
151
|
-
|
|
1
|
+
require 'ffi_yajl'
|
|
2
|
+
|
|
3
|
+
require 'chef_zero/endpoints/rest_object_endpoint'
|
|
4
|
+
require 'chef_zero/chef_data/data_normalizer'
|
|
5
|
+
|
|
6
|
+
module ChefZero
|
|
7
|
+
module Endpoints
|
|
8
|
+
# /policies/:group/:name
|
|
9
|
+
class PoliciesEndpoint < RestObjectEndpoint
|
|
10
|
+
def initialize(server)
|
|
11
|
+
super(server, 'id')
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def get(request)
|
|
15
|
+
already_json_response(200, get_data(request))
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Right now we're allowing PUT to create.
|
|
19
|
+
def put(request)
|
|
20
|
+
error = validate(request)
|
|
21
|
+
return error if error
|
|
22
|
+
|
|
23
|
+
code =
|
|
24
|
+
if data_store.exists?(request.rest_path)
|
|
25
|
+
set_data(request, request.rest_path, request.body, :data_store_exceptions)
|
|
26
|
+
200
|
|
27
|
+
else
|
|
28
|
+
name = request.rest_path[4]
|
|
29
|
+
data_store.create(request.rest_path[0..3], name, request.body, :create_dir)
|
|
30
|
+
201
|
|
31
|
+
end
|
|
32
|
+
already_json_response(code, request.body)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def delete(request)
|
|
36
|
+
result = get_data(request, request.rest_path)
|
|
37
|
+
delete_data(request, request.rest_path, :data_store_exceptions)
|
|
38
|
+
already_json_response(200, result)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def validate(request)
|
|
44
|
+
req_object = validate_json(request.body)
|
|
45
|
+
validate_revision_id(request, req_object) ||
|
|
46
|
+
validate_name(request, req_object) ||
|
|
47
|
+
validate_run_list(req_object) ||
|
|
48
|
+
validate_each_run_list_item(req_object) ||
|
|
49
|
+
validate_cookbook_locks_collection(req_object) ||
|
|
50
|
+
validate_each_cookbook_locks_item(req_object)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def validate_json(request_body)
|
|
54
|
+
FFI_Yajl::Parser.parse(request_body)
|
|
55
|
+
# TODO: rescue parse error, return 400
|
|
56
|
+
# error(400, "Must specify #{identity_keys.map { |k| k.inspect }.join(' or ')} in JSON")
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def validate_revision_id(request, req_object)
|
|
60
|
+
if !req_object.key?("revision_id")
|
|
61
|
+
error(400, "Field 'revision_id' missing")
|
|
62
|
+
elsif req_object["revision_id"].empty?
|
|
63
|
+
error(400, "Field 'revision_id' invalid")
|
|
64
|
+
elsif req_object["revision_id"].size > 255
|
|
65
|
+
error(400, "Field 'revision_id' invalid")
|
|
66
|
+
elsif req_object["revision_id"] !~ /^[\-[:alnum:]_\.\:]+$/
|
|
67
|
+
error(400, "Field 'revision_id' invalid")
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def validate_name(request, req_object)
|
|
72
|
+
if !req_object.key?("name")
|
|
73
|
+
error(400, "Field 'name' missing")
|
|
74
|
+
elsif req_object["name"] != (uri_policy_name = URI.decode(request.rest_path[4]))
|
|
75
|
+
error(400, "Field 'name' invalid : #{uri_policy_name} does not match #{req_object["name"]}")
|
|
76
|
+
elsif req_object["name"].size > 255
|
|
77
|
+
error(400, "Field 'name' invalid")
|
|
78
|
+
elsif req_object["name"] !~ /^[\-[:alnum:]_\.\:]+$/
|
|
79
|
+
error(400, "Field 'name' invalid")
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def validate_run_list(req_object)
|
|
84
|
+
if !req_object.key?("run_list")
|
|
85
|
+
error(400, "Field 'run_list' missing")
|
|
86
|
+
elsif !req_object["run_list"].kind_of?(Array)
|
|
87
|
+
error(400, "Field 'run_list' is not a valid run list")
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def validate_each_run_list_item(req_object)
|
|
92
|
+
req_object["run_list"].each do |run_list_item|
|
|
93
|
+
if res_400 = validate_run_list_item(run_list_item)
|
|
94
|
+
return res_400
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
nil
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def validate_run_list_item(run_list_item)
|
|
101
|
+
if !run_list_item.kind_of?(String)
|
|
102
|
+
error(400, "Field 'run_list' is not a valid run list")
|
|
103
|
+
elsif run_list_item !~ /\Arecipe\[[^\s]+::[^\s]+\]\Z/
|
|
104
|
+
error(400, "Field 'run_list' is not a valid run list")
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def validate_cookbook_locks_collection(req_object)
|
|
109
|
+
if !req_object.key?("cookbook_locks")
|
|
110
|
+
error(400, "Field 'cookbook_locks' missing")
|
|
111
|
+
elsif !req_object["cookbook_locks"].kind_of?(Hash)
|
|
112
|
+
error(400, "Field 'cookbook_locks' invalid")
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def validate_each_cookbook_locks_item(req_object)
|
|
117
|
+
req_object["cookbook_locks"].each do |cookbook_name, lock|
|
|
118
|
+
if res_400 = validate_cookbook_locks_item(cookbook_name, lock)
|
|
119
|
+
return res_400
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
nil
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def validate_cookbook_locks_item(cookbook_name, lock)
|
|
126
|
+
if !lock.kind_of?(Hash)
|
|
127
|
+
error(400, "cookbook_lock entries must be a JSON object")
|
|
128
|
+
elsif !lock.key?("identifier")
|
|
129
|
+
error(400, "Field 'identifier' missing")
|
|
130
|
+
elsif lock["identifier"].size > 255
|
|
131
|
+
error(400, "Field 'identifier' invalid")
|
|
132
|
+
elsif !lock.key?("version")
|
|
133
|
+
error(400, "Field 'version' missing")
|
|
134
|
+
elsif lock.key?("dotted_decimal_identifier")
|
|
135
|
+
unless valid_version?(lock["dotted_decimal_identifier"])
|
|
136
|
+
error(400, "Field 'dotted_decimal_identifier' is not a valid version")
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def valid_version?(version_string)
|
|
142
|
+
Gem::Version.new(version_string)
|
|
143
|
+
true
|
|
144
|
+
rescue ArgumentError
|
|
145
|
+
false
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|