chef-zero 2.0.2 → 2.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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/lib/chef_zero/data_normalizer.rb +6 -2
  3. data/lib/chef_zero/data_store/interface_v1.rb +49 -0
  4. data/lib/chef_zero/data_store/interface_v2.rb +18 -0
  5. data/lib/chef_zero/data_store/memory_store.rb +6 -141
  6. data/lib/chef_zero/data_store/memory_store_v2.rb +188 -0
  7. data/lib/chef_zero/data_store/v1_to_v2_adapter.rb +190 -0
  8. data/lib/chef_zero/data_store/v2_to_v1_adapter.rb +107 -0
  9. data/lib/chef_zero/endpoints/actor_endpoint.rb +6 -12
  10. data/lib/chef_zero/endpoints/authenticate_user_endpoint.rb +1 -1
  11. data/lib/chef_zero/endpoints/cookbook_endpoint.rb +5 -5
  12. data/lib/chef_zero/endpoints/cookbook_version_endpoint.rb +16 -16
  13. data/lib/chef_zero/endpoints/cookbooks_base.rb +5 -5
  14. data/lib/chef_zero/endpoints/cookbooks_endpoint.rb +1 -1
  15. data/lib/chef_zero/endpoints/data_bag_endpoint.rb +2 -2
  16. data/lib/chef_zero/endpoints/data_bag_item_endpoint.rb +1 -1
  17. data/lib/chef_zero/endpoints/data_bags_endpoint.rb +2 -2
  18. data/lib/chef_zero/endpoints/environment_cookbook_endpoint.rb +3 -3
  19. data/lib/chef_zero/endpoints/environment_cookbook_versions_endpoint.rb +9 -9
  20. data/lib/chef_zero/endpoints/environment_cookbooks_endpoint.rb +2 -2
  21. data/lib/chef_zero/endpoints/environment_endpoint.rb +3 -3
  22. data/lib/chef_zero/endpoints/environment_nodes_endpoint.rb +5 -5
  23. data/lib/chef_zero/endpoints/environment_recipes_endpoint.rb +3 -3
  24. data/lib/chef_zero/endpoints/environment_role_endpoint.rb +6 -6
  25. data/lib/chef_zero/endpoints/node_endpoint.rb +1 -1
  26. data/lib/chef_zero/endpoints/principal_endpoint.rb +2 -2
  27. data/lib/chef_zero/endpoints/rest_object_endpoint.rb +3 -3
  28. data/lib/chef_zero/endpoints/role_endpoint.rb +1 -1
  29. data/lib/chef_zero/endpoints/role_environments_endpoint.rb +1 -1
  30. data/lib/chef_zero/endpoints/sandbox_endpoint.rb +3 -3
  31. data/lib/chef_zero/endpoints/sandboxes_endpoint.rb +2 -3
  32. data/lib/chef_zero/endpoints/search_endpoint.rb +13 -9
  33. data/lib/chef_zero/endpoints/searches_endpoint.rb +1 -1
  34. data/lib/chef_zero/rest_base.rb +10 -2
  35. data/lib/chef_zero/rest_request.rb +4 -3
  36. data/lib/chef_zero/server.rb +83 -52
  37. data/lib/chef_zero/version.rb +1 -1
  38. data/spec/run.rb +72 -25
  39. data/spec/support/pedant.rb +4 -0
  40. metadata +10 -5
@@ -0,0 +1,190 @@
1
+ require 'chef_zero/data_store/interface_v2'
2
+
3
+ module ChefZero
4
+ module DataStore
5
+ class V1ToV2Adapter < ChefZero::DataStore::InterfaceV2
6
+ def initialize(real_store, single_org)
7
+ @real_store = real_store
8
+ @single_org = single_org
9
+ # Handle defaults per V2 specification
10
+ @defaults = {
11
+ 'organizations' => {
12
+ single_org => {
13
+ 'clients' => {
14
+ 'chef-validator' => '{ "validator": true }',
15
+ 'chef-webui' => '{ "admin": true }'
16
+ },
17
+ 'environments' => {
18
+ '_default' => '{ "description": "The default Chef environment" }'
19
+ },
20
+ 'users' => {
21
+ 'admin' => '{ "admin": "true" }'
22
+ }
23
+ }
24
+ }
25
+ }
26
+ end
27
+
28
+ attr_reader :real_store
29
+ attr_reader :single_org
30
+
31
+ def clear
32
+ real_store.clear
33
+ end
34
+
35
+ def create_dir(path, name, *options)
36
+ return nil if skip_organizations?(path, name)
37
+ if using_default?(path, name)
38
+ raise DataAlreadyExistsError.new(path + [name])
39
+ end
40
+ fix_exceptions do
41
+ real_store.create_dir(path[2..-1], name, *options)
42
+ end
43
+ end
44
+
45
+ def create(path, name, data, *options)
46
+ return nil if skip_organizations?(path, name)
47
+ if using_default?(path, name)
48
+ raise DataAlreadyExistsError.new(path + [name])
49
+ end
50
+ remove_default(path, name)
51
+
52
+ fix_exceptions do
53
+ real_store.create(path[2..-1], name, data, *options)
54
+ end
55
+ end
56
+
57
+ def get(path, request=nil)
58
+ return nil if skip_organizations?(path)
59
+ if using_default?(path)
60
+ get_default(path)
61
+ else
62
+ fix_exceptions do
63
+ real_store.get(path[2..-1], request)
64
+ end
65
+ end
66
+ end
67
+
68
+ def set(path, data, *options)
69
+ return nil if skip_organizations?(path)
70
+ remove_default(path)
71
+ fix_exceptions do
72
+ real_store.set(path[2..-1], data, *options)
73
+ end
74
+ end
75
+
76
+ def delete(path)
77
+ return nil if skip_organizations?(path)
78
+ remove_default(path)
79
+ fix_exceptions do
80
+ real_store.delete(path[2..-1])
81
+ end
82
+ end
83
+
84
+ def delete_dir(path, *options)
85
+ return nil if skip_organizations?(path)
86
+ fix_exceptions do
87
+ real_store.delete_dir(path[2..-1], *options)
88
+ end
89
+ end
90
+
91
+ def list(path)
92
+ return nil if skip_organizations?(path)
93
+ fix_exceptions do
94
+ result = real_store.list(path[2..-1])
95
+ if using_default?(path)
96
+ result ||= []
97
+ get_default(path).keys.each do |value|
98
+ result << value if !result.include?(value)
99
+ end
100
+ end
101
+ result
102
+ end
103
+ end
104
+
105
+ def exists?(path)
106
+ return nil if skip_organizations?(path)
107
+ if using_default?(path)
108
+ true
109
+ else
110
+ fix_exceptions do
111
+ real_store.exists?(path[2..-1])
112
+ end
113
+ end
114
+ end
115
+
116
+ def exists_dir?(path)
117
+ return nil if skip_organizations?(path)
118
+ if using_default?(path)
119
+ true
120
+ else
121
+ fix_exceptions do
122
+ real_store.exists_dir?(path[2..-1])
123
+ end
124
+ end
125
+ end
126
+
127
+ private
128
+
129
+ def using_default?(path, name = nil)
130
+ path = path + [name] if name
131
+ result = @defaults
132
+ path.each do |part|
133
+ return false if !result.has_key?(part)
134
+ result = result[part]
135
+ end
136
+ !result.nil?
137
+ end
138
+
139
+ def get_default(path, name = nil)
140
+ path = path + [name] if name
141
+ result = @defaults
142
+ path.each do |part|
143
+ return nil if !result.has_key?(part)
144
+ result = result[part]
145
+ end
146
+ result
147
+ end
148
+
149
+ def remove_default(path, name = nil)
150
+ dir = name ? path[0..-2] : path
151
+ default = @defaults
152
+ dir.each do |part|
153
+ return if !default.has_key?(part)
154
+ default = default[part]
155
+ end
156
+
157
+ name = name || path.last
158
+ if name
159
+ default.delete(name)
160
+ end
161
+ end
162
+
163
+ def fix_exceptions
164
+ begin
165
+ yield
166
+ rescue DataAlreadyExistsError => e
167
+ raise DataAlreadyExistsError.new([ 'organizations', single_org ] + e.path, e)
168
+ rescue DataNotFoundError => e
169
+ raise DataNotFoundError.new([ 'organizations', single_org ] + e.path, e)
170
+ end
171
+ end
172
+
173
+ def skip_organizations?(path, name = nil)
174
+ if path == []
175
+ raise "" if name == nil || name != 'organizations'
176
+ true
177
+ elsif path == ['organizations']
178
+ raise "" if name == nil || name != single_org
179
+ true
180
+ else
181
+ raise "Path #{path} must start with /organizations/#{single_org}" if path[0..1] != [ 'organizations', single_org ]
182
+ if !name
183
+ raise "Path #{path} must start with /organizations/#{single_org}/<something>" if path.size <= 2
184
+ end
185
+ false
186
+ end
187
+ end
188
+ end
189
+ end
190
+ end
@@ -0,0 +1,107 @@
1
+ #
2
+ # Author:: John Keiser (<jkeiser@opscode.com>)
3
+ # Copyright:: Copyright (c) 2014 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'chef_zero/data_store/interface_v1'
20
+
21
+ module ChefZero
22
+ module DataStore
23
+ class V2ToV1Adapter < ChefZero::DataStore::InterfaceV1
24
+ def initialize
25
+ @single_org = 'chef'
26
+ end
27
+
28
+ attr_reader :real_store
29
+ attr_reader :single_org
30
+
31
+ def clear
32
+ real_store.clear
33
+ real_store.create_dir([ 'organizations' ], single_org)
34
+ end
35
+
36
+ def create_dir(path, name, *options)
37
+ fix_exceptions do
38
+ real_store.create_dir(fix_path(path), name, *options)
39
+ end
40
+ end
41
+
42
+ def create(path, name, data, *options)
43
+ fix_exceptions do
44
+ real_store.create(fix_path(path), name, data, *options)
45
+ end
46
+ end
47
+
48
+ def get(path, request=nil)
49
+ fix_exceptions do
50
+ real_store.get(fix_path(path), request)
51
+ end
52
+ end
53
+
54
+ def set(path, data, *options)
55
+ fix_exceptions do
56
+ real_store.set(fix_path(path), data, *options)
57
+ end
58
+ end
59
+
60
+ def delete(path)
61
+ fix_exceptions do
62
+ real_store.delete(fix_path(path))
63
+ end
64
+ end
65
+
66
+ def delete_dir(path, *options)
67
+ fix_exceptions do
68
+ real_store.delete_dir(fix_path(path), *options)
69
+ end
70
+ end
71
+
72
+ def list(path)
73
+ fix_exceptions do
74
+ real_store.list(fix_path(path))
75
+ end
76
+ end
77
+
78
+ def exists?(path)
79
+ fix_exceptions do
80
+ real_store.exists?(fix_path(path))
81
+ end
82
+ end
83
+
84
+ def exists_dir?(path)
85
+ fix_exceptions do
86
+ real_store.exists_dir?(fix_path(path))
87
+ end
88
+ end
89
+
90
+ protected
91
+
92
+ def fix_exceptions
93
+ begin
94
+ yield
95
+ rescue DataAlreadyExistsError => e
96
+ raise DataAlreadyExistsError.new(e.path[2..-1], e)
97
+ rescue DataNotFoundError => e
98
+ raise DataNotFoundError.new(e.path[2..-1], e)
99
+ end
100
+ end
101
+
102
+ def fix_path(path)
103
+ [ 'organizations', single_org ] + path
104
+ end
105
+ end
106
+ end
107
+ end
@@ -37,17 +37,12 @@ module ChefZero
37
37
  result = super(request)
38
38
 
39
39
  # Inject private_key into response, delete public_key/password if applicable
40
- if result[0] == 200
40
+ if result[0] == 200 || result[0] == 201
41
41
  response = JSON.parse(result[2], :create_additions => false)
42
42
  response['private_key'] = private_key if private_key
43
- response.delete('public_key') if !updating_public_key && request.rest_path[0] == 'users'
43
+ response.delete('public_key') if !updating_public_key && request.rest_path[2] == 'users'
44
44
  response.delete('password')
45
- # For PUT /clients, a rename returns 201.
46
- if request_body['name'] && request.rest_path[1] != request_body['name']
47
- json_response(201, response)
48
- else
49
- json_response(200, response)
50
- end
45
+ json_response(result[0], response)
51
46
  else
52
47
  result
53
48
  end
@@ -55,14 +50,13 @@ module ChefZero
55
50
 
56
51
  def populate_defaults(request, response_json)
57
52
  response = JSON.parse(response_json, :create_additions => false)
58
- if request.rest_path[0] == 'clients'
59
- response = DataNormalizer.normalize_client(response, request.rest_path[1])
53
+ if request.rest_path[2] == 'clients'
54
+ response = DataNormalizer.normalize_client(response, request.rest_path[3])
60
55
  else
61
- response = DataNormalizer.normalize_user(response, request.rest_path[1])
56
+ response = DataNormalizer.normalize_user(response, request.rest_path[3])
62
57
  end
63
58
  JSON.pretty_generate(response)
64
59
  end
65
60
  end
66
61
  end
67
62
  end
68
-
@@ -10,7 +10,7 @@ module ChefZero
10
10
  name = request_json['name']
11
11
  password = request_json['password']
12
12
  begin
13
- user = data_store.get(['users', name])
13
+ user = data_store.get(request.rest_path[0..1] + ['users', name])
14
14
  verified = JSON.parse(user, :create_additions => false)['password'] == password
15
15
  rescue DataStore::DataNotFoundError
16
16
  verified = false
@@ -5,21 +5,21 @@ module ChefZero
5
5
  # /cookbooks/NAME
6
6
  class CookbookEndpoint < CookbooksBase
7
7
  def get(request)
8
- filter = request.rest_path[1]
8
+ filter = request.rest_path[3]
9
9
  case filter
10
10
  when '_latest'
11
11
  result = {}
12
- filter_cookbooks(all_cookbooks_list, {}, 1) do |name, versions|
12
+ filter_cookbooks(all_cookbooks_list(request), {}, 1) do |name, versions|
13
13
  if versions.size > 0
14
- result[name] = build_uri(request.base_uri, ['cookbooks', name, versions[0]])
14
+ result[name] = build_uri(request.base_uri, request.rest_path[0..1] + ['cookbooks', name, versions[0]])
15
15
  end
16
16
  end
17
17
  json_response(200, result)
18
18
  when '_recipes'
19
19
  result = []
20
- filter_cookbooks(all_cookbooks_list, {}, 1) do |name, versions|
20
+ filter_cookbooks(all_cookbooks_list(request), {}, 1) do |name, versions|
21
21
  if versions.size > 0
22
- cookbook = JSON.parse(get_data(request, ['cookbooks', name, versions[0]]), :create_additions => false)
22
+ cookbook = JSON.parse(get_data(request, request.rest_path[0..1] + ['cookbooks', name, versions[0]]), :create_additions => false)
23
23
  result += recipe_names(name, cookbook)
24
24
  end
25
25
  end
@@ -9,17 +9,17 @@ module ChefZero
9
9
  # /cookbooks/NAME/VERSION
10
10
  class CookbookVersionEndpoint < RestObjectEndpoint
11
11
  def get(request)
12
- if request.rest_path[2] == "_latest" || request.rest_path[2] == "latest"
13
- request.rest_path[2] = latest_version(list_data(request, request.rest_path[0..1]))
12
+ if request.rest_path[4] == "_latest" || request.rest_path[4] == "latest"
13
+ request.rest_path[4] = latest_version(list_data(request, request.rest_path[0..3]))
14
14
  end
15
15
  super(request)
16
16
  end
17
17
 
18
18
  def put(request)
19
- name = request.rest_path[1]
20
- version = request.rest_path[2]
19
+ name = request.rest_path[3]
20
+ version = request.rest_path[4]
21
21
  existing_cookbook = get_data(request, request.rest_path, :nil)
22
-
22
+
23
23
  # Honor frozen
24
24
  if existing_cookbook
25
25
  existing_cookbook_json = JSON.parse(existing_cookbook, :create_additions => false)
@@ -37,7 +37,7 @@ module ChefZero
37
37
  end
38
38
 
39
39
  # Set the cookbook
40
- set_data(request, ['cookbooks', name, version], request.body, :create_dir, :create)
40
+ set_data(request, request.rest_path[0..1] + ['cookbooks', name, version], request.body, :create_dir, :create)
41
41
 
42
42
  # If the cookbook was updated, check for deleted files and clean them up
43
43
  if existing_cookbook
@@ -51,16 +51,16 @@ module ChefZero
51
51
  end
52
52
 
53
53
  def delete(request)
54
- if request.rest_path[2] == "_latest" || request.rest_path[2] == "latest"
55
- request.rest_path[2] = latest_version(list_data(request, request.rest_path[0..1]))
54
+ if request.rest_path[4] == "_latest" || request.rest_path[4] == "latest"
55
+ request.rest_path[4] = latest_version(list_data(request, request.rest_path[0..3]))
56
56
  end
57
57
 
58
58
  deleted_cookbook = get_data(request)
59
59
 
60
60
  response = super(request)
61
- cookbook_name = request.rest_path[1]
62
- if exists_data_dir?(request, [ 'cookbooks', cookbook_name ]) && list_data(request, ['cookbooks', cookbook_name]).size == 0
63
- delete_data_dir(request, ['cookbooks', cookbook_name])
61
+ cookbook_name = request.rest_path[3]
62
+ if exists_data_dir?(request, request.rest_path[0..1] + [ 'cookbooks', cookbook_name ]) && list_data(request, request.rest_path[0..1] + ['cookbooks', cookbook_name]).size == 0
63
+ delete_data_dir(request, request.rest_path[0..1] + ['cookbooks', cookbook_name])
64
64
  end
65
65
 
66
66
  # Hoover deleted files, if they exist
@@ -85,9 +85,9 @@ module ChefZero
85
85
  private
86
86
 
87
87
  def hoover_unused_checksums(deleted_checksums, request)
88
- data_store.list(['cookbooks']).each do |cookbook_name|
89
- data_store.list(['cookbooks', cookbook_name]).each do |version|
90
- cookbook = data_store.get(['cookbooks', cookbook_name, version], request)
88
+ data_store.list(request.rest_path[0..1] + ['cookbooks']).each do |cookbook_name|
89
+ data_store.list(request.rest_path[0..1] + ['cookbooks', cookbook_name]).each do |version|
90
+ cookbook = data_store.get(request.rest_path[0..1] + ['cookbooks', cookbook_name, version], request)
91
91
  deleted_checksums = deleted_checksums - get_checksums(cookbook)
92
92
  end
93
93
  end
@@ -96,7 +96,7 @@ module ChefZero
96
96
  # This deals with an exception on delete, but things can still get deleted
97
97
  # that shouldn't be.
98
98
  begin
99
- data_store.delete(['file_store', 'checksums', checksum])
99
+ data_store.delete(request.rest_path[0..1] + ['file_store', 'checksums', checksum])
100
100
  rescue ChefZero::DataStore::DataNotFoundError
101
101
  end
102
102
  end
@@ -105,7 +105,7 @@ module ChefZero
105
105
  def populate_defaults(request, response_json)
106
106
  # Inject URIs into each cookbook file
107
107
  cookbook = JSON.parse(response_json, :create_additions => false)
108
- cookbook = DataNormalizer.normalize_cookbook(cookbook, request.rest_path[1], request.rest_path[2], request.base_uri, request.method)
108
+ cookbook = DataNormalizer.normalize_cookbook(self, request.rest_path[0..1], cookbook, request.rest_path[3], request.rest_path[4], request.base_uri, request.method)
109
109
  JSON.pretty_generate(cookbook)
110
110
  end
111
111