chef-zero 2.2.1 → 3.0.0.rc.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/README.md +2 -0
- data/Rakefile +5 -1
- data/bin/chef-zero +17 -0
- data/lib/chef_zero/chef_data/acl_path.rb +139 -0
- data/lib/chef_zero/chef_data/cookbook_data.rb +240 -0
- data/lib/chef_zero/chef_data/data_normalizer.rb +207 -0
- data/lib/chef_zero/chef_data/default_creator.rb +446 -0
- data/lib/chef_zero/data_store/default_facade.rb +149 -0
- data/lib/chef_zero/data_store/interface_v1.rb +18 -0
- data/lib/chef_zero/data_store/memory_store.rb +2 -1
- data/lib/chef_zero/data_store/memory_store_v2.rb +3 -36
- data/lib/chef_zero/data_store/raw_file_store.rb +147 -0
- data/lib/chef_zero/data_store/v1_to_v2_adapter.rb +39 -103
- data/lib/chef_zero/data_store/v2_to_v1_adapter.rb +1 -1
- data/lib/chef_zero/endpoints/acl_endpoint.rb +38 -0
- data/lib/chef_zero/endpoints/acls_endpoint.rb +29 -0
- data/lib/chef_zero/endpoints/actor_endpoint.rb +36 -10
- data/lib/chef_zero/endpoints/actors_endpoint.rb +38 -6
- data/lib/chef_zero/endpoints/authenticate_user_endpoint.rb +15 -9
- data/lib/chef_zero/endpoints/container_endpoint.rb +22 -0
- data/lib/chef_zero/endpoints/containers_endpoint.rb +13 -0
- data/lib/chef_zero/endpoints/cookbook_endpoint.rb +1 -1
- data/lib/chef_zero/endpoints/cookbook_version_endpoint.rb +15 -14
- data/lib/chef_zero/endpoints/cookbooks_base.rb +2 -2
- data/lib/chef_zero/endpoints/data_bag_endpoint.rb +4 -4
- data/lib/chef_zero/endpoints/data_bag_item_endpoint.rb +5 -5
- data/lib/chef_zero/endpoints/data_bags_endpoint.rb +5 -4
- data/lib/chef_zero/endpoints/environment_cookbook_endpoint.rb +2 -2
- data/lib/chef_zero/endpoints/environment_cookbook_versions_endpoint.rb +6 -6
- data/lib/chef_zero/endpoints/environment_cookbooks_endpoint.rb +2 -2
- data/lib/chef_zero/endpoints/environment_endpoint.rb +5 -5
- data/lib/chef_zero/endpoints/environment_nodes_endpoint.rb +2 -2
- data/lib/chef_zero/endpoints/environment_recipes_endpoint.rb +3 -3
- data/lib/chef_zero/endpoints/environment_role_endpoint.rb +2 -2
- data/lib/chef_zero/endpoints/file_store_file_endpoint.rb +1 -1
- data/lib/chef_zero/endpoints/group_endpoint.rb +20 -0
- data/lib/chef_zero/endpoints/groups_endpoint.rb +13 -0
- data/lib/chef_zero/endpoints/license_endpoint.rb +25 -0
- data/lib/chef_zero/endpoints/node_endpoint.rb +5 -5
- data/lib/chef_zero/endpoints/not_found_endpoint.rb +2 -2
- data/lib/chef_zero/endpoints/organization_association_request_endpoint.rb +22 -0
- data/lib/chef_zero/endpoints/organization_association_requests_endpoint.rb +29 -0
- data/lib/chef_zero/endpoints/organization_authenticate_user_endpoint.rb +26 -0
- data/lib/chef_zero/endpoints/organization_endpoint.rb +41 -0
- data/lib/chef_zero/endpoints/organization_user_endpoint.rb +48 -0
- data/lib/chef_zero/endpoints/organization_users_endpoint.rb +14 -0
- data/lib/chef_zero/endpoints/organization_validator_key_endpoint.rb +20 -0
- data/lib/chef_zero/endpoints/organizations_endpoint.rb +55 -0
- data/lib/chef_zero/endpoints/principal_endpoint.rb +15 -3
- data/lib/chef_zero/endpoints/rest_list_endpoint.rb +8 -6
- data/lib/chef_zero/endpoints/rest_object_endpoint.rb +12 -10
- data/lib/chef_zero/endpoints/role_endpoint.rb +5 -5
- data/lib/chef_zero/endpoints/role_environments_endpoint.rb +2 -2
- data/lib/chef_zero/endpoints/sandbox_endpoint.rb +2 -2
- data/lib/chef_zero/endpoints/sandboxes_endpoint.rb +4 -4
- data/lib/chef_zero/endpoints/search_endpoint.rb +10 -10
- data/lib/chef_zero/endpoints/system_recovery_endpoint.rb +30 -0
- data/lib/chef_zero/endpoints/user_association_request_endpoint.rb +40 -0
- data/lib/chef_zero/endpoints/user_association_requests_count_endpoint.rb +19 -0
- data/lib/chef_zero/endpoints/user_association_requests_endpoint.rb +19 -0
- data/lib/chef_zero/endpoints/user_organizations_endpoint.rb +22 -0
- data/lib/chef_zero/rest_base.rb +79 -13
- data/lib/chef_zero/rest_error_response.rb +1 -1
- data/lib/chef_zero/rest_request.rb +4 -0
- data/lib/chef_zero/rest_router.rb +1 -0
- data/lib/chef_zero/rspec.rb +55 -8
- data/lib/chef_zero/server.rb +87 -21
- data/lib/chef_zero/version.rb +1 -1
- data/spec/run_oc_pedant.rb +53 -0
- data/spec/{run.rb → run_pedant.rb} +13 -4
- data/spec/server_spec.rb +54 -0
- data/spec/support/oc_pedant.rb +134 -0
- data/spec/support/pedant.rb +1 -1
- metadata +54 -13
- data/lib/chef_zero/cookbook_data.rb +0 -236
- data/lib/chef_zero/data_normalizer.rb +0 -146
@@ -0,0 +1,207 @@
|
|
1
|
+
require 'chef_zero'
|
2
|
+
require 'chef_zero/rest_base'
|
3
|
+
require 'chef_zero/chef_data/default_creator'
|
4
|
+
|
5
|
+
module ChefZero
|
6
|
+
module ChefData
|
7
|
+
class DataNormalizer
|
8
|
+
def self.normalize_acls(acls)
|
9
|
+
ChefData::DefaultCreator::PERMISSIONS.each do |perm|
|
10
|
+
acls[perm] ||= {}
|
11
|
+
acls[perm]['actors'] ||= []
|
12
|
+
acls[perm]['groups'] ||= []
|
13
|
+
end
|
14
|
+
acls
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.normalize_client(client, name)
|
18
|
+
client['name'] ||= name
|
19
|
+
client['admin'] ||= false
|
20
|
+
client['admin'] = !!client['admin']
|
21
|
+
client['public_key'] ||= PUBLIC_KEY
|
22
|
+
client['validator'] ||= false
|
23
|
+
client['validator'] = !!client['validator']
|
24
|
+
client['json_class'] ||= "Chef::ApiClient"
|
25
|
+
client['chef_type'] ||= "client"
|
26
|
+
client
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.normalize_container(container, name)
|
30
|
+
container.delete('id')
|
31
|
+
container['containername'] = name
|
32
|
+
container['containerpath'] = name
|
33
|
+
container
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.normalize_user(user, name, identity_keys, osc_compat, method=nil)
|
37
|
+
user[identity_keys.first] ||= name
|
38
|
+
user['public_key'] ||= PUBLIC_KEY
|
39
|
+
user['admin'] ||= false
|
40
|
+
user['admin'] = !!user['admin']
|
41
|
+
user['openid'] ||= nil
|
42
|
+
if !osc_compat
|
43
|
+
if method == 'GET'
|
44
|
+
user.delete('admin')
|
45
|
+
user.delete('password')
|
46
|
+
user.delete('openid')
|
47
|
+
end
|
48
|
+
user['email'] ||= nil
|
49
|
+
user['first_name'] ||= nil
|
50
|
+
user['last_name'] ||= nil
|
51
|
+
end
|
52
|
+
user
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.normalize_data_bag_item(data_bag_item, data_bag_name, id, method)
|
56
|
+
if method == 'DELETE'
|
57
|
+
# TODO SERIOUSLY, WHO DOES THIS MANY EXCEPTIONS IN THEIR INTERFACE
|
58
|
+
if !(data_bag_item['json_class'] == 'Chef::DataBagItem' && data_bag_item['raw_data'])
|
59
|
+
data_bag_item['id'] ||= id
|
60
|
+
data_bag_item = { 'raw_data' => data_bag_item }
|
61
|
+
data_bag_item['chef_type'] ||= 'data_bag_item'
|
62
|
+
data_bag_item['json_class'] ||= 'Chef::DataBagItem'
|
63
|
+
data_bag_item['data_bag'] ||= data_bag_name
|
64
|
+
data_bag_item['name'] ||= "data_bag_item_#{data_bag_name}_#{id}"
|
65
|
+
end
|
66
|
+
else
|
67
|
+
# If it's not already wrapped with raw_data, wrap it.
|
68
|
+
if data_bag_item['json_class'] == 'Chef::DataBagItem' && data_bag_item['raw_data']
|
69
|
+
data_bag_item = data_bag_item['raw_data']
|
70
|
+
end
|
71
|
+
# Argh. We don't do this on GET, but we do on PUT and POST????
|
72
|
+
if %w(PUT POST).include?(method)
|
73
|
+
data_bag_item['chef_type'] ||= 'data_bag_item'
|
74
|
+
data_bag_item['data_bag'] ||= data_bag_name
|
75
|
+
end
|
76
|
+
data_bag_item['id'] ||= id
|
77
|
+
end
|
78
|
+
data_bag_item
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.normalize_cookbook(endpoint, org_prefix, cookbook, name, version, base_uri, method)
|
82
|
+
# TODO I feel dirty
|
83
|
+
if method != 'PUT'
|
84
|
+
cookbook.each_pair do |key, value|
|
85
|
+
if value.is_a?(Array)
|
86
|
+
value.each do |file|
|
87
|
+
if file.is_a?(Hash) && file.has_key?('checksum')
|
88
|
+
file['url'] ||= endpoint.build_uri(base_uri, org_prefix + ['file_store', 'checksums', file['checksum']])
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
cookbook['name'] ||= "#{name}-#{version}"
|
94
|
+
# TODO this feels wrong, but the real chef server doesn't expand this default
|
95
|
+
# cookbook['version'] ||= version
|
96
|
+
cookbook['cookbook_name'] ||= name
|
97
|
+
cookbook['frozen?'] ||= false
|
98
|
+
cookbook['metadata'] ||= {}
|
99
|
+
cookbook['metadata']['version'] ||= version
|
100
|
+
# Sad to not be expanding defaults just because Chef doesn't :(
|
101
|
+
# cookbook['metadata']['name'] ||= name
|
102
|
+
# cookbook['metadata']['description'] ||= "A fabulous new cookbook"
|
103
|
+
cookbook['metadata']['long_description'] ||= ""
|
104
|
+
# cookbook['metadata']['maintainer'] ||= "YOUR_COMPANY_NAME"
|
105
|
+
# cookbook['metadata']['maintainer_email'] ||= "YOUR_EMAIL"
|
106
|
+
# cookbook['metadata']['license'] ||= "none"
|
107
|
+
cookbook['metadata']['dependencies'] ||= {}
|
108
|
+
cookbook['metadata']['attributes'] ||= {}
|
109
|
+
cookbook['metadata']['recipes'] ||= {}
|
110
|
+
end
|
111
|
+
cookbook['json_class'] ||= 'Chef::CookbookVersion'
|
112
|
+
cookbook['chef_type'] ||= 'cookbook_version'
|
113
|
+
if method == 'MIN'
|
114
|
+
cookbook['metadata'].delete('attributes')
|
115
|
+
cookbook['metadata'].delete('long_description')
|
116
|
+
end
|
117
|
+
cookbook
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.normalize_environment(environment, name)
|
121
|
+
environment['name'] ||= name
|
122
|
+
environment['description'] ||= ''
|
123
|
+
environment['cookbook_versions'] ||= {}
|
124
|
+
environment['json_class'] ||= "Chef::Environment"
|
125
|
+
environment['chef_type'] ||= "environment"
|
126
|
+
environment['default_attributes'] ||= {}
|
127
|
+
environment['override_attributes'] ||= {}
|
128
|
+
environment
|
129
|
+
end
|
130
|
+
|
131
|
+
def self.normalize_group(group, name, orgname)
|
132
|
+
group.delete('id')
|
133
|
+
if group['actors'].is_a?(Hash)
|
134
|
+
group['users'] ||= group['actors']['users']
|
135
|
+
group['clients'] ||= group['actors']['clients']
|
136
|
+
group['groups'] ||= group['actors']['groups']
|
137
|
+
group['actors'] = nil
|
138
|
+
end
|
139
|
+
group['users'] ||= []
|
140
|
+
group['clients'] ||= []
|
141
|
+
group['actors'] ||= (group['clients'] + group['users'])
|
142
|
+
group['groups'] ||= []
|
143
|
+
group['orgname'] ||= orgname if orgname
|
144
|
+
group['name'] ||= name
|
145
|
+
group['groupname'] ||= name
|
146
|
+
|
147
|
+
group['users'].uniq!
|
148
|
+
group['clients'].uniq!
|
149
|
+
group['actors'].uniq!
|
150
|
+
group['groups'].uniq!
|
151
|
+
group
|
152
|
+
end
|
153
|
+
|
154
|
+
def self.normalize_node(node, name)
|
155
|
+
node['name'] ||= name
|
156
|
+
node['json_class'] ||= 'Chef::Node'
|
157
|
+
node['chef_type'] ||= 'node'
|
158
|
+
node['chef_environment'] ||= '_default'
|
159
|
+
node['override'] ||= {}
|
160
|
+
node['normal'] ||= {}
|
161
|
+
node['default'] ||= {}
|
162
|
+
node['automatic'] ||= {}
|
163
|
+
node['run_list'] ||= []
|
164
|
+
node['run_list'] = normalize_run_list(node['run_list'])
|
165
|
+
node
|
166
|
+
end
|
167
|
+
|
168
|
+
def self.normalize_organization(org, name)
|
169
|
+
org['name'] ||= name
|
170
|
+
org['full_name'] ||= name
|
171
|
+
org['org_type'] ||= 'Business'
|
172
|
+
org['clientname'] ||= "#{name}-validator"
|
173
|
+
org['billing_plan'] ||= 'platform-free'
|
174
|
+
org
|
175
|
+
end
|
176
|
+
|
177
|
+
def self.normalize_role(role, name)
|
178
|
+
role['name'] ||= name
|
179
|
+
role['description'] ||= ''
|
180
|
+
role['json_class'] ||= 'Chef::Role'
|
181
|
+
role['chef_type'] ||= 'role'
|
182
|
+
role['default_attributes'] ||= {}
|
183
|
+
role['override_attributes'] ||= {}
|
184
|
+
role['run_list'] ||= []
|
185
|
+
role['run_list'] = normalize_run_list(role['run_list'])
|
186
|
+
role['env_run_lists'] ||= {}
|
187
|
+
role['env_run_lists'].each_pair do |env, run_list|
|
188
|
+
role['env_run_lists'][env] = normalize_run_list(run_list)
|
189
|
+
end
|
190
|
+
role
|
191
|
+
end
|
192
|
+
|
193
|
+
def self.normalize_run_list(run_list)
|
194
|
+
run_list.map{|item|
|
195
|
+
case item
|
196
|
+
when /^recipe\[.*\]$/
|
197
|
+
item # explicit recipe
|
198
|
+
when /^role\[.*\]$/
|
199
|
+
item # explicit role
|
200
|
+
else
|
201
|
+
"recipe[#{item}]"
|
202
|
+
end
|
203
|
+
}.uniq
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
@@ -0,0 +1,446 @@
|
|
1
|
+
require 'chef_zero/chef_data/acl_path'
|
2
|
+
|
3
|
+
module ChefZero
|
4
|
+
module ChefData
|
5
|
+
#
|
6
|
+
# The DefaultCreator creates default values when you ask for them.
|
7
|
+
# - It relies on created and deleted being called when things get
|
8
|
+
# created and deleted, so that it knows the owners of said objects
|
9
|
+
# and knows to eliminate default values on delete.
|
10
|
+
# - get, list and exists? get data.
|
11
|
+
#
|
12
|
+
class DefaultCreator
|
13
|
+
def initialize(data, single_org, osc_compat, superusers = nil)
|
14
|
+
@data = data
|
15
|
+
@single_org = single_org
|
16
|
+
@osc_compat = osc_compat
|
17
|
+
@superusers = superusers || DEFAULT_SUPERUSERS
|
18
|
+
clear
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_reader :data
|
22
|
+
attr_reader :single_org
|
23
|
+
attr_reader :osc_compat
|
24
|
+
attr_reader :creators
|
25
|
+
attr_reader :deleted
|
26
|
+
|
27
|
+
PERMISSIONS = %w(create read update delete grant)
|
28
|
+
DEFAULT_SUPERUSERS = %w(pivotal)
|
29
|
+
|
30
|
+
def clear
|
31
|
+
@creators = { [] => @superusers }
|
32
|
+
@deleted = {}
|
33
|
+
end
|
34
|
+
|
35
|
+
def deleted(path)
|
36
|
+
# acl deletes mean nothing, they are entirely subservient to their
|
37
|
+
# parent object
|
38
|
+
if path[0] == 'acls' || (path[0] == 'organizations' && path[2] == 'acls')
|
39
|
+
return false
|
40
|
+
end
|
41
|
+
|
42
|
+
result = exists?(path)
|
43
|
+
@deleted[path] = true
|
44
|
+
result
|
45
|
+
end
|
46
|
+
|
47
|
+
def deleted?(path)
|
48
|
+
1.upto(path.size) do |index|
|
49
|
+
return true if @deleted[path[0..-index]]
|
50
|
+
end
|
51
|
+
false
|
52
|
+
end
|
53
|
+
|
54
|
+
def created(path, creator, create_parents)
|
55
|
+
# If a parent has been deleted, we will need to clear that.
|
56
|
+
deleted_index = nil
|
57
|
+
0.upto(path.size-1) do |index|
|
58
|
+
deleted_index = index if @deleted[path[0..index]]
|
59
|
+
end
|
60
|
+
|
61
|
+
# Walk up the tree, setting the creator on anything that doesn't exist
|
62
|
+
# (anything that is either deleted or was never created)
|
63
|
+
while (deleted_index && path.size > deleted_index) || !@creators[path]
|
64
|
+
@creators[path] = creator ? [ creator ] : []
|
65
|
+
@deleted.delete(path)
|
66
|
+
# Only do this once if create_parents is false
|
67
|
+
break if !create_parents || path.size == 0
|
68
|
+
|
69
|
+
path = path[0..-2]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def superusers
|
74
|
+
@creators[[]]
|
75
|
+
end
|
76
|
+
|
77
|
+
def get(path)
|
78
|
+
return nil if deleted?(path)
|
79
|
+
|
80
|
+
result = case path[0]
|
81
|
+
when 'acls'
|
82
|
+
# /acls/*
|
83
|
+
object_path = AclPath.get_object_path(path)
|
84
|
+
if data_exists?(object_path)
|
85
|
+
default_acl(path)
|
86
|
+
end
|
87
|
+
|
88
|
+
when 'containers'
|
89
|
+
if path.size == 2 && exists?(path)
|
90
|
+
{}
|
91
|
+
end
|
92
|
+
|
93
|
+
when 'users'
|
94
|
+
if path.size == 2 && data.exists?(path)
|
95
|
+
# User is empty user
|
96
|
+
{}
|
97
|
+
end
|
98
|
+
|
99
|
+
when 'organizations'
|
100
|
+
if path.size >= 2
|
101
|
+
# /organizations/*/**
|
102
|
+
if data.exists_dir?(path[0..1])
|
103
|
+
get_org_default(path)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
result
|
109
|
+
end
|
110
|
+
|
111
|
+
def list(path)
|
112
|
+
return nil if deleted?(path)
|
113
|
+
|
114
|
+
if path.size == 0
|
115
|
+
return %w(containers users organizations acls)
|
116
|
+
end
|
117
|
+
|
118
|
+
case path[0]
|
119
|
+
when 'acls'
|
120
|
+
if path.size == 1
|
121
|
+
[ 'root' ] + (data.list(path + [ 'containers' ]) - [ 'organizations' ])
|
122
|
+
else
|
123
|
+
data.list(AclPath.get_object_path(path))
|
124
|
+
end
|
125
|
+
|
126
|
+
when 'containers'
|
127
|
+
[ 'containers', 'users', 'organizations' ]
|
128
|
+
|
129
|
+
when 'users'
|
130
|
+
superusers
|
131
|
+
|
132
|
+
when 'organizations'
|
133
|
+
if path.size == 1
|
134
|
+
single_org ? [ single_org ] : []
|
135
|
+
elsif path.size >= 2 && data.exists_dir?(path[0..1])
|
136
|
+
list_org_default(path)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def exists?(path)
|
142
|
+
return true if path.size == 0
|
143
|
+
parent_list = list(path[0..-2])
|
144
|
+
parent_list && parent_list.include?(path[-1])
|
145
|
+
end
|
146
|
+
|
147
|
+
protected
|
148
|
+
|
149
|
+
DEFAULT_ORG_SPINE = {
|
150
|
+
'clients' => {},
|
151
|
+
'cookbooks' => {},
|
152
|
+
'data' => {},
|
153
|
+
'environments' => %w(_default),
|
154
|
+
'file_store' => {
|
155
|
+
'checksums' => {}
|
156
|
+
},
|
157
|
+
'nodes' => {},
|
158
|
+
'roles' => {},
|
159
|
+
'sandboxes' => {},
|
160
|
+
'users' => {},
|
161
|
+
|
162
|
+
'org' => {},
|
163
|
+
'containers' => %w(clients containers cookbooks data environments groups nodes roles sandboxes),
|
164
|
+
'groups' => %w(admins billing-admins clients users),
|
165
|
+
'association_requests' => {}
|
166
|
+
}
|
167
|
+
|
168
|
+
def list_org_default(path)
|
169
|
+
if path.size >= 3 && path[2] == 'acls'
|
170
|
+
if path.size == 3
|
171
|
+
# /organizations/ORG/acls
|
172
|
+
return [ 'root' ] + data.list(path[0..1] + [ 'containers' ])
|
173
|
+
elsif path.size == 4
|
174
|
+
# /organizations/ORG/acls/TYPE
|
175
|
+
return data.list(path[0..1] + [ path[3] ])
|
176
|
+
else
|
177
|
+
return nil
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
value = DEFAULT_ORG_SPINE
|
182
|
+
2.upto(path.size-1) do |index|
|
183
|
+
value = nil if @deleted[path[0..index]]
|
184
|
+
break if !value
|
185
|
+
value = value[path[index]]
|
186
|
+
end
|
187
|
+
|
188
|
+
result = if value.is_a?(Hash)
|
189
|
+
value.keys
|
190
|
+
elsif value
|
191
|
+
value
|
192
|
+
end
|
193
|
+
|
194
|
+
if path.size == 3
|
195
|
+
if path[2] == 'clients'
|
196
|
+
result << "#{path[1]}-validator"
|
197
|
+
if osc_compat
|
198
|
+
result << "#{path[1]}-webui"
|
199
|
+
end
|
200
|
+
elsif path[2] == 'users'
|
201
|
+
if osc_compat
|
202
|
+
result << 'admin'
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
result
|
208
|
+
end
|
209
|
+
|
210
|
+
def get_org_default(path)
|
211
|
+
if path[2] == 'acls'
|
212
|
+
get_org_acl_default(path)
|
213
|
+
|
214
|
+
elsif path.size >= 4
|
215
|
+
if path[2] == 'containers' && path.size == 4
|
216
|
+
if exists?(path)
|
217
|
+
return {}
|
218
|
+
else
|
219
|
+
return nil
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
# /organizations/(*)/clients/\1-validator
|
224
|
+
# /organizations/*/environments/_default
|
225
|
+
# /organizations/*/groups/{admins,billing-admins,clients,users}
|
226
|
+
case path[2..-1].join('/')
|
227
|
+
when "clients/#{path[1]}-validator"
|
228
|
+
{ 'validator' => 'true' }
|
229
|
+
|
230
|
+
when "clients/#{path[1]}-webui", "users/admin"
|
231
|
+
if osc_compat
|
232
|
+
{ 'admin' => 'true' }
|
233
|
+
end
|
234
|
+
|
235
|
+
when "environments/_default"
|
236
|
+
{ "description" => "The default Chef environment" }
|
237
|
+
|
238
|
+
when "groups/admins"
|
239
|
+
admins = data.list(path[0..1] + [ 'users' ]).select do |name|
|
240
|
+
user = JSON.parse(data.get(path[0..1] + [ 'users', name ]), :create_additions => false)
|
241
|
+
user['admin']
|
242
|
+
end
|
243
|
+
admins += data.list(path[0..1] + [ 'clients' ]).select do |name|
|
244
|
+
client = JSON.parse(data.get(path[0..1] + [ 'clients', name ]), :create_additions => false)
|
245
|
+
client['admin']
|
246
|
+
end
|
247
|
+
admins += @creators[path[0..1]] if @creators[path[0..1]]
|
248
|
+
{ 'actors' => admins.uniq }
|
249
|
+
|
250
|
+
when "groups/billing-admins"
|
251
|
+
{}
|
252
|
+
|
253
|
+
when "groups/clients"
|
254
|
+
{ 'clients' => data.list(path[0..1] + [ 'clients' ]) }
|
255
|
+
|
256
|
+
when "groups/users"
|
257
|
+
users = data.list(path[0..1] + [ 'users' ])
|
258
|
+
users |= @creators[path[0..1]] if @creators[path[0..1]]
|
259
|
+
{ 'users' => users }
|
260
|
+
|
261
|
+
when "org"
|
262
|
+
{}
|
263
|
+
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
def get_org_acl_default(path)
|
269
|
+
object_path = AclPath.get_object_path(path)
|
270
|
+
# The actual things containers correspond to don't have to exist, as long as the container does
|
271
|
+
return nil if object_path[2] != 'containers' && !data_exists?(object_path)
|
272
|
+
basic_acl =
|
273
|
+
case path[3..-1].join('/')
|
274
|
+
when 'root', 'containers/containers', 'containers/groups'
|
275
|
+
{
|
276
|
+
'create' => { 'groups' => %w(admins) },
|
277
|
+
'read' => { 'groups' => %w(admins users) },
|
278
|
+
'update' => { 'groups' => %w(admins) },
|
279
|
+
'delete' => { 'groups' => %w(admins) },
|
280
|
+
'grant' => { 'groups' => %w(admins) },
|
281
|
+
}
|
282
|
+
when 'containers/cookbooks', 'containers/environments', 'containers/roles'
|
283
|
+
{
|
284
|
+
'create' => { 'groups' => %w(admins users) },
|
285
|
+
'read' => { 'groups' => %w(admins users clients) },
|
286
|
+
'update' => { 'groups' => %w(admins users) },
|
287
|
+
'delete' => { 'groups' => %w(admins users) },
|
288
|
+
'grant' => { 'groups' => %w(admins) },
|
289
|
+
}
|
290
|
+
when 'containers/cookbooks', 'containers/data'
|
291
|
+
{
|
292
|
+
'create' => { 'groups' => %w(admins users clients) },
|
293
|
+
'read' => { 'groups' => %w(admins users clients) },
|
294
|
+
'update' => { 'groups' => %w(admins users clients) },
|
295
|
+
'delete' => { 'groups' => %w(admins users clients) },
|
296
|
+
'grant' => { 'groups' => %w(admins) },
|
297
|
+
}
|
298
|
+
when 'containers/nodes'
|
299
|
+
{
|
300
|
+
'create' => { 'groups' => %w(admins users clients) },
|
301
|
+
'read' => { 'groups' => %w(admins users clients) },
|
302
|
+
'update' => { 'groups' => %w(admins users) },
|
303
|
+
'delete' => { 'groups' => %w(admins users) },
|
304
|
+
'grant' => { 'groups' => %w(admins) },
|
305
|
+
}
|
306
|
+
when 'containers/clients'
|
307
|
+
{
|
308
|
+
'create' => { 'groups' => %w(admins) },
|
309
|
+
'read' => { 'groups' => %w(admins users) },
|
310
|
+
'update' => { 'groups' => %w(admins) },
|
311
|
+
'delete' => { 'groups' => %w(admins users) },
|
312
|
+
'grant' => { 'groups' => %w(admins) },
|
313
|
+
}
|
314
|
+
when 'containers/sandboxes'
|
315
|
+
{
|
316
|
+
'create' => { 'groups' => %w(admins users) },
|
317
|
+
'read' => { 'groups' => %w(admins) },
|
318
|
+
'update' => { 'groups' => %w(admins) },
|
319
|
+
'delete' => { 'groups' => %w(admins) },
|
320
|
+
'grant' => { 'groups' => %w(admins) },
|
321
|
+
}
|
322
|
+
when 'groups/admins', 'groups/clients', 'groups/users'
|
323
|
+
{
|
324
|
+
'create' => { 'groups' => %w(admins) },
|
325
|
+
'read' => { 'groups' => %w(admins) },
|
326
|
+
'update' => { 'groups' => %w(admins) },
|
327
|
+
'delete' => { 'groups' => %w(admins) },
|
328
|
+
'grant' => { 'groups' => %w(admins) },
|
329
|
+
}
|
330
|
+
when 'groups/billing-admins'
|
331
|
+
{
|
332
|
+
'create' => { 'groups' => %w() },
|
333
|
+
'read' => { 'groups' => %w(billing-admins) },
|
334
|
+
'update' => { 'groups' => %w(billing-admins) },
|
335
|
+
'delete' => { 'groups' => %w() },
|
336
|
+
'grant' => { 'groups' => %w() },
|
337
|
+
}
|
338
|
+
else
|
339
|
+
{}
|
340
|
+
end
|
341
|
+
|
342
|
+
default_acl(path, basic_acl)
|
343
|
+
end
|
344
|
+
|
345
|
+
def get_owners(acl_path)
|
346
|
+
owners = []
|
347
|
+
|
348
|
+
path = AclPath.get_object_path(acl_path)
|
349
|
+
if path
|
350
|
+
|
351
|
+
# Non-validator clients own themselves.
|
352
|
+
if path.size == 4 && path[0] == 'organizations' && path[2] == 'clients'
|
353
|
+
begin
|
354
|
+
client = JSON.parse(data.get(path), :create_additions => false)
|
355
|
+
if !client['validator']
|
356
|
+
owners |= [ path[3] ]
|
357
|
+
end
|
358
|
+
rescue
|
359
|
+
owners |= [ path[3] ]
|
360
|
+
end
|
361
|
+
|
362
|
+
# Add creators as owners (except any validator clients).
|
363
|
+
if @creators[path]
|
364
|
+
@creators[path].each do |creator|
|
365
|
+
begin
|
366
|
+
client = JSON.parse(data.get(path[0..2] + [ creator ]), :create_additions => false)
|
367
|
+
next if client['validator']
|
368
|
+
rescue
|
369
|
+
end
|
370
|
+
owners |= [ creator ]
|
371
|
+
end
|
372
|
+
end
|
373
|
+
else
|
374
|
+
owners |= @creators[path] if @creators[path]
|
375
|
+
end
|
376
|
+
|
377
|
+
#ANGRY
|
378
|
+
# Non-default containers do not get superusers added to them,
|
379
|
+
# because reasons.
|
380
|
+
unless path.size == 4 && path[0] == 'organizations' && path[2] == 'containers' && !exists?(path)
|
381
|
+
owners |= superusers
|
382
|
+
end
|
383
|
+
end
|
384
|
+
|
385
|
+
owners.uniq
|
386
|
+
end
|
387
|
+
|
388
|
+
def default_acl(acl_path, acl={})
|
389
|
+
owners = nil
|
390
|
+
container_acl = nil
|
391
|
+
PERMISSIONS.each do |perm|
|
392
|
+
acl[perm] ||= {}
|
393
|
+
acl[perm]['actors'] ||= begin
|
394
|
+
owners ||= get_owners(acl_path)
|
395
|
+
end
|
396
|
+
acl[perm]['groups'] ||= begin
|
397
|
+
# When we create containers, we don't merge groups (not sure why).
|
398
|
+
if acl_path[0] == 'organizations' && acl_path[3] == 'containers'
|
399
|
+
[]
|
400
|
+
else
|
401
|
+
container_acl ||= get_container_acl(acl_path) || {}
|
402
|
+
(container_acl[perm] ? container_acl[perm]['groups'] : []) || []
|
403
|
+
end
|
404
|
+
end
|
405
|
+
end
|
406
|
+
acl
|
407
|
+
end
|
408
|
+
|
409
|
+
def get_container_acl(acl_path)
|
410
|
+
parent_path = AclPath.parent_acl_data_path(acl_path)
|
411
|
+
if parent_path
|
412
|
+
JSON.parse(data.get(parent_path), :create_additions => false)
|
413
|
+
else
|
414
|
+
nil
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
418
|
+
def data_exists?(path)
|
419
|
+
if is_dir?(path)
|
420
|
+
data.exists_dir?(path)
|
421
|
+
else
|
422
|
+
data.exists?(path)
|
423
|
+
end
|
424
|
+
end
|
425
|
+
|
426
|
+
def is_dir?(path)
|
427
|
+
case path.size
|
428
|
+
when 0, 1
|
429
|
+
return true
|
430
|
+
when 2
|
431
|
+
return path[0] == 'organizations' || (path[0] == 'acls' && path[1] != 'root')
|
432
|
+
when 3
|
433
|
+
# If it has a container, it is a directory.
|
434
|
+
return path[0] == 'organizations' &&
|
435
|
+
(path[2] == 'acls' || data.exists?(path[0..1] + [ 'containers', path[2] ]))
|
436
|
+
when 4
|
437
|
+
return path[0] == 'organizations' && (
|
438
|
+
(path[2] == 'acls' && path[1] != 'root') ||
|
439
|
+
%w(cookbooks data).include?(path[2]))
|
440
|
+
else
|
441
|
+
return false
|
442
|
+
end
|
443
|
+
end
|
444
|
+
end
|
445
|
+
end
|
446
|
+
end
|