chef-zero 4.3.0 → 4.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +201 -201
  3. data/README.md +155 -155
  4. data/Rakefile +31 -31
  5. data/bin/chef-zero +100 -100
  6. data/lib/chef_zero.rb +10 -10
  7. data/lib/chef_zero/chef_data/acl_path.rb +139 -139
  8. data/lib/chef_zero/chef_data/cookbook_data.rb +240 -240
  9. data/lib/chef_zero/chef_data/data_normalizer.rb +208 -207
  10. data/lib/chef_zero/chef_data/default_creator.rb +446 -446
  11. data/lib/chef_zero/data_store/data_already_exists_error.rb +29 -29
  12. data/lib/chef_zero/data_store/data_error.rb +31 -31
  13. data/lib/chef_zero/data_store/data_not_found_error.rb +28 -28
  14. data/lib/chef_zero/data_store/default_facade.rb +149 -149
  15. data/lib/chef_zero/data_store/interface_v1.rb +67 -67
  16. data/lib/chef_zero/data_store/interface_v2.rb +18 -18
  17. data/lib/chef_zero/data_store/memory_store.rb +33 -33
  18. data/lib/chef_zero/data_store/memory_store_v2.rb +155 -155
  19. data/lib/chef_zero/data_store/raw_file_store.rb +147 -147
  20. data/lib/chef_zero/data_store/v1_to_v2_adapter.rb +142 -142
  21. data/lib/chef_zero/data_store/v2_to_v1_adapter.rb +107 -107
  22. data/lib/chef_zero/endpoints/acl_endpoint.rb +38 -38
  23. data/lib/chef_zero/endpoints/acls_endpoint.rb +29 -29
  24. data/lib/chef_zero/endpoints/actor_endpoint.rb +94 -94
  25. data/lib/chef_zero/endpoints/actors_endpoint.rb +64 -64
  26. data/lib/chef_zero/endpoints/authenticate_user_endpoint.rb +31 -31
  27. data/lib/chef_zero/endpoints/container_endpoint.rb +22 -22
  28. data/lib/chef_zero/endpoints/containers_endpoint.rb +13 -13
  29. data/lib/chef_zero/endpoints/cookbook_endpoint.rb +39 -39
  30. data/lib/chef_zero/endpoints/cookbook_version_endpoint.rb +119 -119
  31. data/lib/chef_zero/endpoints/cookbooks_base.rb +65 -65
  32. data/lib/chef_zero/endpoints/cookbooks_endpoint.rb +19 -19
  33. data/lib/chef_zero/endpoints/data_bag_endpoint.rb +45 -45
  34. data/lib/chef_zero/endpoints/data_bag_item_endpoint.rb +25 -25
  35. data/lib/chef_zero/endpoints/data_bags_endpoint.rb +23 -23
  36. data/lib/chef_zero/endpoints/environment_cookbook_endpoint.rb +24 -24
  37. data/lib/chef_zero/endpoints/environment_cookbook_versions_endpoint.rb +123 -123
  38. data/lib/chef_zero/endpoints/environment_cookbooks_endpoint.rb +22 -22
  39. data/lib/chef_zero/endpoints/environment_endpoint.rb +33 -33
  40. data/lib/chef_zero/endpoints/environment_nodes_endpoint.rb +23 -23
  41. data/lib/chef_zero/endpoints/environment_recipes_endpoint.rb +22 -22
  42. data/lib/chef_zero/endpoints/environment_role_endpoint.rb +36 -36
  43. data/lib/chef_zero/endpoints/file_store_file_endpoint.rb +22 -22
  44. data/lib/chef_zero/endpoints/group_endpoint.rb +20 -20
  45. data/lib/chef_zero/endpoints/groups_endpoint.rb +13 -13
  46. data/lib/chef_zero/endpoints/license_endpoint.rb +25 -25
  47. data/lib/chef_zero/endpoints/node_endpoint.rb +17 -17
  48. data/lib/chef_zero/endpoints/node_identifiers_endpoint.rb +22 -22
  49. data/lib/chef_zero/endpoints/not_found_endpoint.rb +11 -11
  50. data/lib/chef_zero/endpoints/organization_association_request_endpoint.rb +22 -22
  51. data/lib/chef_zero/endpoints/organization_association_requests_endpoint.rb +30 -30
  52. data/lib/chef_zero/endpoints/organization_authenticate_user_endpoint.rb +26 -26
  53. data/lib/chef_zero/endpoints/organization_endpoint.rb +46 -46
  54. data/lib/chef_zero/endpoints/organization_user_base.rb +15 -15
  55. data/lib/chef_zero/endpoints/organization_user_endpoint.rb +26 -26
  56. data/lib/chef_zero/endpoints/organization_users_endpoint.rb +43 -43
  57. data/lib/chef_zero/endpoints/organization_validator_key_endpoint.rb +20 -20
  58. data/lib/chef_zero/endpoints/organizations_endpoint.rb +62 -62
  59. data/lib/chef_zero/endpoints/policies_endpoint.rb +151 -151
  60. data/lib/chef_zero/endpoints/principal_endpoint.rb +42 -42
  61. data/lib/chef_zero/endpoints/rest_list_endpoint.rb +42 -42
  62. data/lib/chef_zero/endpoints/rest_object_endpoint.rb +63 -63
  63. data/lib/chef_zero/endpoints/role_endpoint.rb +16 -16
  64. data/lib/chef_zero/endpoints/role_environments_endpoint.rb +14 -14
  65. data/lib/chef_zero/endpoints/sandbox_endpoint.rb +27 -27
  66. data/lib/chef_zero/endpoints/sandboxes_endpoint.rb +50 -50
  67. data/lib/chef_zero/endpoints/search_endpoint.rb +194 -194
  68. data/lib/chef_zero/endpoints/searches_endpoint.rb +18 -18
  69. data/lib/chef_zero/endpoints/server_api_version_endpoint.rb +14 -14
  70. data/lib/chef_zero/endpoints/system_recovery_endpoint.rb +30 -30
  71. data/lib/chef_zero/endpoints/user_association_request_endpoint.rb +40 -40
  72. data/lib/chef_zero/endpoints/user_association_requests_count_endpoint.rb +19 -19
  73. data/lib/chef_zero/endpoints/user_association_requests_endpoint.rb +19 -19
  74. data/lib/chef_zero/endpoints/user_organizations_endpoint.rb +22 -22
  75. data/lib/chef_zero/endpoints/version_endpoint.rb +12 -12
  76. data/lib/chef_zero/log.rb +7 -7
  77. data/lib/chef_zero/rest_base.rb +242 -242
  78. data/lib/chef_zero/rest_error_response.rb +11 -11
  79. data/lib/chef_zero/rest_request.rb +69 -69
  80. data/lib/chef_zero/rest_router.rb +45 -45
  81. data/lib/chef_zero/rspec.rb +308 -308
  82. data/lib/chef_zero/server.rb +642 -642
  83. data/lib/chef_zero/socketless_server_map.rb +92 -92
  84. data/lib/chef_zero/solr/query/binary_operator.rb +52 -52
  85. data/lib/chef_zero/solr/query/phrase.rb +23 -23
  86. data/lib/chef_zero/solr/query/range_query.rb +46 -46
  87. data/lib/chef_zero/solr/query/regexpable_query.rb +29 -29
  88. data/lib/chef_zero/solr/query/subquery.rb +37 -37
  89. data/lib/chef_zero/solr/query/term.rb +45 -45
  90. data/lib/chef_zero/solr/query/unary_operator.rb +43 -43
  91. data/lib/chef_zero/solr/solr_doc.rb +53 -53
  92. data/lib/chef_zero/solr/solr_parser.rb +203 -203
  93. data/lib/chef_zero/version.rb +3 -3
  94. data/spec/run_oc_pedant.rb +63 -63
  95. data/spec/search_spec.rb +32 -32
  96. data/spec/server_spec.rb +92 -92
  97. data/spec/socketless_server_map_spec.rb +76 -76
  98. data/spec/support/oc_pedant.rb +132 -132
  99. data/spec/support/stickywicket.pem +27 -27
  100. metadata +3 -3
@@ -1,207 +1,208 @@
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, orgname = nil)
18
- client['name'] ||= name
19
- client['clientname'] ||= name
20
- client['public_key'] ||= PUBLIC_KEY
21
- client['orgname'] ||= orgname
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
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, orgname = nil)
18
+ client['name'] ||= name
19
+ client['clientname'] ||= name
20
+ client['admin'] = !!client['admin'] if client.has_key?('admin')
21
+ client['public_key'] ||= PUBLIC_KEY
22
+ client['orgname'] ||= orgname
23
+ client['validator'] ||= false
24
+ client['validator'] = !!client['validator']
25
+ client['json_class'] ||= "Chef::ApiClient"
26
+ client['chef_type'] ||= "client"
27
+ client
28
+ end
29
+
30
+ def self.normalize_container(container, name)
31
+ container.delete('id')
32
+ container['containername'] = name
33
+ container['containerpath'] = name
34
+ container
35
+ end
36
+
37
+ def self.normalize_user(user, name, identity_keys, osc_compat, method=nil)
38
+ user[identity_keys.first] ||= name
39
+ user['public_key'] ||= PUBLIC_KEY
40
+ user['admin'] ||= false
41
+ user['admin'] = !!user['admin']
42
+ user['openid'] ||= nil
43
+ if !osc_compat
44
+ if method == 'GET'
45
+ user.delete('admin')
46
+ user.delete('password')
47
+ user.delete('openid')
48
+ end
49
+ user['email'] ||= nil
50
+ user['first_name'] ||= nil
51
+ user['last_name'] ||= nil
52
+ end
53
+ user
54
+ end
55
+
56
+ def self.normalize_data_bag_item(data_bag_item, data_bag_name, id, method)
57
+ if method == 'DELETE'
58
+ # TODO SERIOUSLY, WHO DOES THIS MANY EXCEPTIONS IN THEIR INTERFACE
59
+ if !(data_bag_item['json_class'] == 'Chef::DataBagItem' && data_bag_item['raw_data'])
60
+ data_bag_item['id'] ||= id
61
+ data_bag_item = { 'raw_data' => data_bag_item }
62
+ data_bag_item['chef_type'] ||= 'data_bag_item'
63
+ data_bag_item['json_class'] ||= 'Chef::DataBagItem'
64
+ data_bag_item['data_bag'] ||= data_bag_name
65
+ data_bag_item['name'] ||= "data_bag_item_#{data_bag_name}_#{id}"
66
+ end
67
+ else
68
+ # If it's not already wrapped with raw_data, wrap it.
69
+ if data_bag_item['json_class'] == 'Chef::DataBagItem' && data_bag_item['raw_data']
70
+ data_bag_item = data_bag_item['raw_data']
71
+ end
72
+ # Argh. We don't do this on GET, but we do on PUT and POST????
73
+ if %w(PUT POST).include?(method)
74
+ data_bag_item['chef_type'] ||= 'data_bag_item'
75
+ data_bag_item['data_bag'] ||= data_bag_name
76
+ end
77
+ data_bag_item['id'] ||= id
78
+ end
79
+ data_bag_item
80
+ end
81
+
82
+ def self.normalize_cookbook(endpoint, org_prefix, cookbook, name, version, base_uri, method)
83
+ # TODO I feel dirty
84
+ if method != 'PUT'
85
+ cookbook.each_pair do |key, value|
86
+ if value.is_a?(Array)
87
+ value.each do |file|
88
+ if file.is_a?(Hash) && file.has_key?('checksum')
89
+ file['url'] ||= endpoint.build_uri(base_uri, org_prefix + ['file_store', 'checksums', file['checksum']])
90
+ end
91
+ end
92
+ end
93
+ end
94
+ cookbook['name'] ||= "#{name}-#{version}"
95
+ # TODO this feels wrong, but the real chef server doesn't expand this default
96
+ # cookbook['version'] ||= version
97
+ cookbook['cookbook_name'] ||= name
98
+ cookbook['frozen?'] ||= false
99
+ cookbook['metadata'] ||= {}
100
+ cookbook['metadata']['version'] ||= version
101
+ # Sad to not be expanding defaults just because Chef doesn't :(
102
+ # cookbook['metadata']['name'] ||= name
103
+ # cookbook['metadata']['description'] ||= "A fabulous new cookbook"
104
+ cookbook['metadata']['long_description'] ||= ""
105
+ # cookbook['metadata']['maintainer'] ||= "YOUR_COMPANY_NAME"
106
+ # cookbook['metadata']['maintainer_email'] ||= "YOUR_EMAIL"
107
+ # cookbook['metadata']['license'] ||= "none"
108
+ cookbook['metadata']['dependencies'] ||= {}
109
+ cookbook['metadata']['attributes'] ||= {}
110
+ cookbook['metadata']['recipes'] ||= {}
111
+ end
112
+ cookbook['json_class'] ||= 'Chef::CookbookVersion'
113
+ cookbook['chef_type'] ||= 'cookbook_version'
114
+ if method == 'MIN'
115
+ cookbook['metadata'].delete('attributes')
116
+ cookbook['metadata'].delete('long_description')
117
+ end
118
+ cookbook
119
+ end
120
+
121
+ def self.normalize_environment(environment, name)
122
+ environment['name'] ||= name
123
+ environment['description'] ||= ''
124
+ environment['cookbook_versions'] ||= {}
125
+ environment['json_class'] ||= "Chef::Environment"
126
+ environment['chef_type'] ||= "environment"
127
+ environment['default_attributes'] ||= {}
128
+ environment['override_attributes'] ||= {}
129
+ environment
130
+ end
131
+
132
+ def self.normalize_group(group, name, orgname)
133
+ group.delete('id')
134
+ if group['actors'].is_a?(Hash)
135
+ group['users'] ||= group['actors']['users']
136
+ group['clients'] ||= group['actors']['clients']
137
+ group['groups'] ||= group['actors']['groups']
138
+ group['actors'] = nil
139
+ end
140
+ group['users'] ||= []
141
+ group['clients'] ||= []
142
+ group['actors'] ||= (group['clients'] + group['users'])
143
+ group['groups'] ||= []
144
+ group['orgname'] ||= orgname if orgname
145
+ group['name'] ||= name
146
+ group['groupname'] ||= name
147
+
148
+ group['users'].uniq!
149
+ group['clients'].uniq!
150
+ group['actors'].uniq!
151
+ group['groups'].uniq!
152
+ group
153
+ end
154
+
155
+ def self.normalize_node(node, name)
156
+ node['name'] ||= name
157
+ node['json_class'] ||= 'Chef::Node'
158
+ node['chef_type'] ||= 'node'
159
+ node['chef_environment'] ||= '_default'
160
+ node['override'] ||= {}
161
+ node['normal'] ||= {}
162
+ node['default'] ||= {}
163
+ node['automatic'] ||= {}
164
+ node['run_list'] ||= []
165
+ node['run_list'] = normalize_run_list(node['run_list'])
166
+ node
167
+ end
168
+
169
+ def self.normalize_organization(org, name)
170
+ org['name'] ||= name
171
+ org['full_name'] ||= name
172
+ org['org_type'] ||= 'Business'
173
+ org['clientname'] ||= "#{name}-validator"
174
+ org['billing_plan'] ||= 'platform-free'
175
+ org
176
+ end
177
+
178
+ def self.normalize_role(role, name)
179
+ role['name'] ||= name
180
+ role['description'] ||= ''
181
+ role['json_class'] ||= 'Chef::Role'
182
+ role['chef_type'] ||= 'role'
183
+ role['default_attributes'] ||= {}
184
+ role['override_attributes'] ||= {}
185
+ role['run_list'] ||= []
186
+ role['run_list'] = normalize_run_list(role['run_list'])
187
+ role['env_run_lists'] ||= {}
188
+ role['env_run_lists'].each_pair do |env, run_list|
189
+ role['env_run_lists'][env] = normalize_run_list(run_list)
190
+ end
191
+ role
192
+ end
193
+
194
+ def self.normalize_run_list(run_list)
195
+ run_list.map{|item|
196
+ case item
197
+ when /^recipe\[.*\]$/
198
+ item # explicit recipe
199
+ when /^role\[.*\]$/
200
+ item # explicit role
201
+ else
202
+ "recipe[#{item}]"
203
+ end
204
+ }.uniq
205
+ end
206
+ end
207
+ end
208
+ end
@@ -1,446 +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 policies cookbook_artifacts),
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 = FFI_Yajl::Parser.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 = FFI_Yajl::Parser.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 !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 = FFI_Yajl::Parser.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 = FFI_Yajl::Parser.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
- FFI_Yajl::Parser.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
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 policies cookbook_artifacts),
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 = FFI_Yajl::Parser.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 = FFI_Yajl::Parser.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 !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 = FFI_Yajl::Parser.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 = FFI_Yajl::Parser.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
+ FFI_Yajl::Parser.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