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
@@ -2,11 +2,13 @@ require 'rack/request'
2
2
 
3
3
  module ChefZero
4
4
  class RestRequest
5
- def initialize(env)
5
+ def initialize(env, rest_base_prefix = [])
6
6
  @env = env
7
+ @rest_base_prefix = rest_base_prefix
7
8
  end
8
9
 
9
10
  attr_reader :env
11
+ attr_reader :rest_base_prefix
10
12
 
11
13
  def base_uri
12
14
  @base_uri ||= "#{env['rack.url_scheme']}://#{env['HTTP_HOST']}#{env['SCRIPT_NAME']}"
@@ -17,7 +19,7 @@ module ChefZero
17
19
  end
18
20
 
19
21
  def rest_path
20
- @rest_path ||= env['PATH_INFO'].split('/').select { |part| part != "" }
22
+ @rest_path ||= rest_base_prefix + env['PATH_INFO'].split('/').select { |part| part != "" }
21
23
  end
22
24
 
23
25
  def body=(body)
@@ -53,4 +55,3 @@ module ChefZero
53
55
  end
54
56
  end
55
57
  end
56
-
@@ -28,7 +28,8 @@ require 'webrick'
28
28
  require 'chef_zero'
29
29
  require 'chef_zero/cookbook_data'
30
30
  require 'chef_zero/rest_router'
31
- require 'chef_zero/data_store/memory_store'
31
+ require 'chef_zero/data_store/memory_store_v2'
32
+ require 'chef_zero/data_store/v1_to_v2_adapter'
32
33
  require 'chef_zero/version'
33
34
 
34
35
  require 'chef_zero/endpoints/authenticate_user_endpoint'
@@ -65,7 +66,8 @@ module ChefZero
65
66
  :host => '127.0.0.1',
66
67
  :port => 8889,
67
68
  :log_level => :info,
68
- :generate_real_keys => true
69
+ :generate_real_keys => true,
70
+ :single_org => 'chef'
69
71
  }.freeze
70
72
 
71
73
  def initialize(options = {})
@@ -102,10 +104,25 @@ module ChefZero
102
104
  #
103
105
  # The data store for this server (default is in-memory).
104
106
  #
105
- # @return [~ChefZero::DataStore]
107
+ # @return [ChefZero::DataStore]
106
108
  #
107
109
  def data_store
108
- @data_store ||= @options[:data_store] || DataStore::MemoryStore.new
110
+ @data_store ||= begin
111
+ result = @options[:data_store] || DataStore::MemoryStoreV2.new
112
+ if options[:single_org]
113
+ if result.respond_to?(:interface_version) && result.interface_version >= 2 && result.interface_version < 3
114
+ result.create_dir([ 'organizations' ], options[:single_org])
115
+ else
116
+ result = ChefZero::DataStore::V1ToV2Adapter.new(result, options[:single_org])
117
+ end
118
+ else
119
+ if !(result.respond_to?(:interface_version) && result.interface_version >= 2 && result.interface_version < 3)
120
+ raise "Multi-org not supported by data store #{result}!"
121
+ end
122
+ end
123
+
124
+ result
125
+ end
109
126
  end
110
127
 
111
128
  #
@@ -123,8 +140,8 @@ module ChefZero
123
140
  # Start a Chef Zero server in the current thread. You can stop this server
124
141
  # by canceling the current thread.
125
142
  #
126
- # @param [Boolean] publish
127
- # publish the server information to STDOUT
143
+ # @param [Boolean|IO] publish
144
+ # publish the server information to the publish parameter or to STDOUT if it's "true"
128
145
  #
129
146
  # @return [nil]
130
147
  # this method will block the main thread until interrupted
@@ -133,7 +150,8 @@ module ChefZero
133
150
  publish = publish[:publish] if publish.is_a?(Hash) # Legacy API
134
151
 
135
152
  if publish
136
- puts <<-EOH.gsub(/^ {10}/, '')
153
+ output = publish.respond_to?(:puts) ? publish : STDOUT
154
+ output.puts <<-EOH.gsub(/^ {10}/, '')
137
155
  >> Starting Chef Zero (v#{ChefZero::VERSION})...
138
156
  >> WEBrick (v#{WEBrick::VERSION}) on Rack (v#{Rack.release}) is listening at #{url}
139
157
  >> Press CTRL+C to stop
@@ -208,9 +226,9 @@ module ChefZero
208
226
  # server
209
227
  #
210
228
  def stop(wait = 5)
211
- Timeout.timeout(wait) do
229
+ if @thread
212
230
  @server.shutdown
213
- @thread.join(wait) if @thread
231
+ @thread.join(wait)
214
232
  end
215
233
  rescue Timeout::Error
216
234
  if @thread
@@ -265,19 +283,20 @@ module ChefZero
265
283
  # }
266
284
  # }
267
285
  # }
268
- def load_data(contents)
286
+ def load_data(contents, org_name = 'chef')
287
+ data_store.create_dir('organizations', org_name)
269
288
  %w(clients environments nodes roles users).each do |data_type|
270
289
  if contents[data_type]
271
290
  dejsonize_children(contents[data_type]).each_pair do |name, data|
272
- data_store.set([data_type, name], data, :create)
291
+ data_store.set(['organizations', org_name, data_type, name], data, :create)
273
292
  end
274
293
  end
275
294
  end
276
295
  if contents['data']
277
296
  contents['data'].each_pair do |key, data_bag|
278
- data_store.create_dir(['data'], key, :recursive)
297
+ data_store.create_dir(['organizations', org_name, 'data'], key, :recursive)
279
298
  dejsonize_children(data_bag).each do |item_name, item|
280
- data_store.set(['data', key, item_name], item, :create)
299
+ data_store.set(['organizations', org_name, 'data', key, item_name], item, :create)
281
300
  end
282
301
  end
283
302
  end
@@ -289,12 +308,12 @@ module ChefZero
289
308
  cookbook_data = CookbookData.to_hash(cookbook, name_version)
290
309
  end
291
310
  raise "No version specified" if !cookbook_data[:version]
292
- data_store.create_dir(['cookbooks'], cookbook_data[:cookbook_name], :recursive)
293
- data_store.set(['cookbooks', cookbook_data[:cookbook_name], cookbook_data[:version]], JSON.pretty_generate(cookbook_data), :create)
311
+ data_store.create_dir(['organizations', org_name, 'cookbooks'], cookbook_data[:cookbook_name], :recursive)
312
+ data_store.set(['organizations', org_name, 'cookbooks', cookbook_data[:cookbook_name], cookbook_data[:version]], JSON.pretty_generate(cookbook_data), :create)
294
313
  cookbook_data.values.each do |files|
295
314
  next unless files.is_a? Array
296
315
  files.each do |file|
297
- data_store.set(['file_store', 'checksums', file[:checksum]], get_file(cookbook, file[:path]), :create)
316
+ data_store.set(['organizations', org_name, 'file_store', 'checksums', file[:checksum]], get_file(cookbook, file[:path]), :create)
298
317
  end
299
318
  end
300
319
  end
@@ -303,6 +322,9 @@ module ChefZero
303
322
 
304
323
  def clear_data
305
324
  data_store.clear
325
+ if options[:single_org]
326
+ data_store.create_dir([ 'organizations' ], options[:single_org])
327
+ end
306
328
  end
307
329
 
308
330
  def request_handler(&block)
@@ -319,45 +341,54 @@ module ChefZero
319
341
 
320
342
  private
321
343
 
344
+ def open_source_endpoints
345
+ [
346
+ [ "/organizations/*/authenticate_user", AuthenticateUserEndpoint.new(self) ],
347
+ [ "/organizations/*/clients", ActorsEndpoint.new(self) ],
348
+ [ "/organizations/*/clients/*", ActorEndpoint.new(self) ],
349
+ [ "/organizations/*/cookbooks", CookbooksEndpoint.new(self) ],
350
+ [ "/organizations/*/cookbooks/*", CookbookEndpoint.new(self) ],
351
+ [ "/organizations/*/cookbooks/*/*", CookbookVersionEndpoint.new(self) ],
352
+ [ "/organizations/*/data", DataBagsEndpoint.new(self) ],
353
+ [ "/organizations/*/data/*", DataBagEndpoint.new(self) ],
354
+ [ "/organizations/*/data/*/*", DataBagItemEndpoint.new(self) ],
355
+ [ "/organizations/*/environments", RestListEndpoint.new(self) ],
356
+ [ "/organizations/*/environments/*", EnvironmentEndpoint.new(self) ],
357
+ [ "/organizations/*/environments/*/cookbooks", EnvironmentCookbooksEndpoint.new(self) ],
358
+ [ "/organizations/*/environments/*/cookbooks/*", EnvironmentCookbookEndpoint.new(self) ],
359
+ [ "/organizations/*/environments/*/cookbook_versions", EnvironmentCookbookVersionsEndpoint.new(self) ],
360
+ [ "/organizations/*/environments/*/nodes", EnvironmentNodesEndpoint.new(self) ],
361
+ [ "/organizations/*/environments/*/recipes", EnvironmentRecipesEndpoint.new(self) ],
362
+ [ "/organizations/*/environments/*/roles/*", EnvironmentRoleEndpoint.new(self) ],
363
+ [ "/organizations/*/nodes", RestListEndpoint.new(self) ],
364
+ [ "/organizations/*/nodes/*", NodeEndpoint.new(self) ],
365
+ [ "/organizations/*/principals/*", PrincipalEndpoint.new(self) ],
366
+ [ "/organizations/*/roles", RestListEndpoint.new(self) ],
367
+ [ "/organizations/*/roles/*", RoleEndpoint.new(self) ],
368
+ [ "/organizations/*/roles/*/environments", RoleEnvironmentsEndpoint.new(self) ],
369
+ [ "/organizations/*/roles/*/environments/*", EnvironmentRoleEndpoint.new(self) ],
370
+ [ "/organizations/*/sandboxes", SandboxesEndpoint.new(self) ],
371
+ [ "/organizations/*/sandboxes/*", SandboxEndpoint.new(self) ],
372
+ [ "/organizations/*/search", SearchesEndpoint.new(self) ],
373
+ [ "/organizations/*/search/*", SearchEndpoint.new(self) ],
374
+ [ "/organizations/*/users", ActorsEndpoint.new(self) ],
375
+ [ "/organizations/*/users/*", ActorEndpoint.new(self) ],
376
+
377
+ [ "/organizations/*/file_store/**", FileStoreFileEndpoint.new(self) ],
378
+ ]
379
+ end
380
+
322
381
  def app
323
- router = RestRouter.new([
324
- [ '/authenticate_user', AuthenticateUserEndpoint.new(self) ],
325
- [ '/clients', ActorsEndpoint.new(self) ],
326
- [ '/clients/*', ActorEndpoint.new(self) ],
327
- [ '/cookbooks', CookbooksEndpoint.new(self) ],
328
- [ '/cookbooks/*', CookbookEndpoint.new(self) ],
329
- [ '/cookbooks/*/*', CookbookVersionEndpoint.new(self) ],
330
- [ '/data', DataBagsEndpoint.new(self) ],
331
- [ '/data/*', DataBagEndpoint.new(self) ],
332
- [ '/data/*/*', DataBagItemEndpoint.new(self) ],
333
- [ '/environments', RestListEndpoint.new(self) ],
334
- [ '/environments/*', EnvironmentEndpoint.new(self) ],
335
- [ '/environments/*/cookbooks', EnvironmentCookbooksEndpoint.new(self) ],
336
- [ '/environments/*/cookbooks/*', EnvironmentCookbookEndpoint.new(self) ],
337
- [ '/environments/*/cookbook_versions', EnvironmentCookbookVersionsEndpoint.new(self) ],
338
- [ '/environments/*/nodes', EnvironmentNodesEndpoint.new(self) ],
339
- [ '/environments/*/recipes', EnvironmentRecipesEndpoint.new(self) ],
340
- [ '/environments/*/roles/*', EnvironmentRoleEndpoint.new(self) ],
341
- [ '/nodes', RestListEndpoint.new(self) ],
342
- [ '/nodes/*', NodeEndpoint.new(self) ],
343
- [ '/principals/*', PrincipalEndpoint.new(self) ],
344
- [ '/roles', RestListEndpoint.new(self) ],
345
- [ '/roles/*', RoleEndpoint.new(self) ],
346
- [ '/roles/*/environments', RoleEnvironmentsEndpoint.new(self) ],
347
- [ '/roles/*/environments/*', EnvironmentRoleEndpoint.new(self) ],
348
- [ '/sandboxes', SandboxesEndpoint.new(self) ],
349
- [ '/sandboxes/*', SandboxEndpoint.new(self) ],
350
- [ '/search', SearchesEndpoint.new(self) ],
351
- [ '/search/*', SearchEndpoint.new(self) ],
352
- [ '/users', ActorsEndpoint.new(self) ],
353
- [ '/users/*', ActorEndpoint.new(self) ],
354
-
355
- [ '/file_store/**', FileStoreFileEndpoint.new(self) ],
356
- ])
382
+ router = RestRouter.new(open_source_endpoints)
357
383
  router.not_found = NotFoundEndpoint.new
358
384
 
385
+ if options[:single_org]
386
+ rest_base_prefix = [ 'organizations', 'chef' ]
387
+ else
388
+ rest_base_prefix = []
389
+ end
359
390
  return proc do |env|
360
- request = RestRequest.new(env)
391
+ request = RestRequest.new(env, rest_base_prefix)
361
392
  if @on_request_proc
362
393
  @on_request_proc.call(request)
363
394
  end
@@ -387,7 +418,7 @@ module ChefZero
387
418
  def dejsonize_children(hash)
388
419
  result = {}
389
420
  hash.each_pair do |key, value|
390
- result[key] = value.is_a?(Hash) ? JSON.pretty_generate(value) : value
421
+ result[key] = value.is_a?(Hash) ? JSON.pretty_generate(value) : value
391
422
  end
392
423
  result
393
424
  end
@@ -1,3 +1,3 @@
1
1
  module ChefZero
2
- VERSION = '2.0.2'
2
+ VERSION = '2.1'
3
3
  end
data/spec/run.rb CHANGED
@@ -5,33 +5,80 @@ require 'bundler/setup'
5
5
  require 'chef_zero/server'
6
6
  require 'rspec/core'
7
7
 
8
- server = ChefZero::Server.new(:port => 8889)
9
- server.start_background
10
-
11
- unless ENV['SKIP_PEDANT']
12
- require 'pedant'
13
- require 'pedant/opensource'
14
-
15
- Pedant.config.suite = 'api'
16
- Pedant.config[:config_file] = 'spec/support/pedant.rb'
17
- Pedant.setup([
18
- '--skip-validation',
19
- '--skip-authentication',
20
- '--skip-authorization',
21
- '--skip-omnibus'
22
- ])
23
-
24
- result = RSpec::Core::Runner.run(Pedant.config.rspec_args)
25
- else
26
- require 'net/http'
27
- response = Net::HTTP.new('127.0.0.1', 8889).get("/environments", { 'Accept' => 'application/json'}).body
28
- if response =~ /_default/
29
- result = 0
8
+ tmpdir = nil
9
+
10
+ def start_server(chef_repo_path)
11
+ Dir.mkdir(chef_repo_path) if !File.exists?(chef_repo_path)
12
+
13
+ # 11.6 and below had a bug where it couldn't create the repo children automatically
14
+ if Chef::VERSION.to_f < 11.8
15
+ %w(clients cookbooks data_bags environments nodes roles users).each do |child|
16
+ Dir.mkdir("#{chef_repo_path}/#{child}") if !File.exists?("#{chef_repo_path}/#{child}")
17
+ end
18
+ end
19
+
20
+ # Start the new server
21
+ Chef::Config.repo_mode = 'everything'
22
+ Chef::Config.chef_repo_path = chef_repo_path
23
+ Chef::Config.versioned_cookbooks = true
24
+ chef_fs = Chef::ChefFS::Config.new.local_fs
25
+ data_store = Chef::ChefFS::ChefFSDataStore.new(chef_fs)
26
+ server = ChefZero::Server.new(:port => 8889, :data_store => data_store)#, :log_level => :debug)
27
+ server.start_background
28
+ server
29
+ end
30
+
31
+ begin
32
+ if ENV['CHEF_FS']
33
+ require 'chef/chef_fs/chef_fs_data_store'
34
+ require 'chef/chef_fs/config'
35
+ require 'tmpdir'
36
+ require 'fileutils'
37
+ require 'chef/version'
38
+
39
+ # Create chef repository
40
+ tmpdir = Dir.mktmpdir
41
+ chef_repo_path = "#{tmpdir}/repo"
42
+
43
+ # Capture setup data into master_chef_repo_path
44
+ server = start_server(chef_repo_path)
45
+
46
+ else
47
+ server = ChefZero::Server.new(:port => 8889)
48
+ server.start_background
49
+ end
50
+
51
+ unless ENV['SKIP_PEDANT']
52
+ require 'pedant'
53
+ require 'pedant/opensource'
54
+
55
+ #Pedant::Config.rerun = true
56
+
57
+ Pedant.config.suite = 'api'
58
+ Pedant.config[:config_file] = 'spec/support/pedant.rb'
59
+ Pedant.setup([
60
+ '--skip-knife',
61
+ '--skip-validation',
62
+ '--skip-authentication',
63
+ '--skip-authorization',
64
+ '--skip-omnibus'
65
+ ])
66
+
67
+ result = RSpec::Core::Runner.run(Pedant.config.rspec_args)
30
68
  else
31
- puts "GET /environments returned #{response}. Expected _default!"
32
- result = 1
69
+ require 'net/http'
70
+ response = Net::HTTP.new('127.0.0.1', 8889).get("/environments", { 'Accept' => 'application/json'}).body
71
+ if response =~ /_default/
72
+ result = 0
73
+ else
74
+ puts "GET /environments returned #{response}. Expected _default!"
75
+ result = 1
76
+ end
33
77
  end
78
+
79
+ server.stop if server.running?
80
+ ensure
81
+ FileUtils.remove_entry_secure(tmpdir) if tmpdir
34
82
  end
35
83
 
36
- server.stop
37
84
  exit(result)
@@ -41,6 +41,10 @@ chef_server 'http://127.0.0.1:8889'
41
41
  # differs significantly from this.
42
42
  maximum_search_time 0
43
43
 
44
+ # OSC sends erchef a host header with a port, so this option needs
45
+ # # to be enabled for Pedant tests to work correctly
46
+ explicit_port_url true
47
+
44
48
  # We're starting to break tests up into groups based on different
45
49
  # criteria. The proper API tests (the results of which are viewable
46
50
  # to OPC customers) should be the only ones run by Pedant embedded in
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chef-zero
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.2
4
+ version: '2.1'
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Keiser
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-21 00:00:00.000000000 Z
11
+ date: 2014-05-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mixlib-log
@@ -105,14 +105,17 @@ files:
105
105
  - LICENSE
106
106
  - README.md
107
107
  - Rakefile
108
- - bin/chef-zero
109
- - lib/chef_zero.rb
110
108
  - lib/chef_zero/cookbook_data.rb
111
109
  - lib/chef_zero/data_normalizer.rb
112
110
  - lib/chef_zero/data_store/data_already_exists_error.rb
113
111
  - lib/chef_zero/data_store/data_error.rb
114
112
  - lib/chef_zero/data_store/data_not_found_error.rb
113
+ - lib/chef_zero/data_store/interface_v1.rb
114
+ - lib/chef_zero/data_store/interface_v2.rb
115
115
  - lib/chef_zero/data_store/memory_store.rb
116
+ - lib/chef_zero/data_store/memory_store_v2.rb
117
+ - lib/chef_zero/data_store/v1_to_v2_adapter.rb
118
+ - lib/chef_zero/data_store/v2_to_v1_adapter.rb
116
119
  - lib/chef_zero/endpoints/actor_endpoint.rb
117
120
  - lib/chef_zero/endpoints/actors_endpoint.rb
118
121
  - lib/chef_zero/endpoints/authenticate_user_endpoint.rb
@@ -159,10 +162,12 @@ files:
159
162
  - lib/chef_zero/solr/solr_doc.rb
160
163
  - lib/chef_zero/solr/solr_parser.rb
161
164
  - lib/chef_zero/version.rb
165
+ - lib/chef_zero.rb
162
166
  - spec/run.rb
163
167
  - spec/search_spec.rb
164
168
  - spec/support/pedant.rb
165
169
  - spec/support/stickywicket.pem
170
+ - bin/chef-zero
166
171
  homepage: http://www.opscode.com
167
172
  licenses:
168
173
  - Apache 2.0
@@ -183,7 +188,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
183
188
  version: '0'
184
189
  requirements: []
185
190
  rubyforge_project:
186
- rubygems_version: 2.2.1
191
+ rubygems_version: 2.0.3
187
192
  signing_key:
188
193
  specification_version: 4
189
194
  summary: Self-contained, easy-setup, fast-start in-memory Chef server for testing