chef 11.12.0.alpha.1-x86-mingw32 → 11.12.0.rc.1-x86-mingw32

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 (121) hide show
  1. checksums.yaml +4 -4
  2. data/lib/chef/api_client/registration.rb +46 -9
  3. data/lib/chef/application.rb +1 -0
  4. data/lib/chef/application/client.rb +25 -24
  5. data/lib/chef/client.rb +34 -0
  6. data/lib/chef/config.rb +11 -0
  7. data/lib/chef/cookbook/chefignore.rb +10 -2
  8. data/lib/chef/cookbook/metadata.rb +31 -3
  9. data/lib/chef/cookbook/synchronizer.rb +2 -2
  10. data/lib/chef/cookbook/syntax_check.rb +4 -4
  11. data/lib/chef/encrypted_data_bag_item.rb +37 -1
  12. data/lib/chef/exceptions.rb +1 -0
  13. data/lib/chef/guard_interpreter/default_guard_interpreter.rb +42 -0
  14. data/lib/chef/guard_interpreter/resource_guard_interpreter.rb +122 -0
  15. data/lib/chef/http.rb +0 -1
  16. data/lib/chef/http/decompressor.rb +7 -4
  17. data/lib/chef/http/simple.rb +5 -0
  18. data/lib/chef/http/validate_content_length.rb +28 -12
  19. data/lib/chef/knife.rb +1 -0
  20. data/lib/chef/knife/client_bulk_delete.rb +48 -9
  21. data/lib/chef/knife/client_delete.rb +4 -4
  22. data/lib/chef/knife/cookbook_bulk_delete.rb +1 -1
  23. data/lib/chef/knife/cookbook_upload.rb +17 -7
  24. data/lib/chef/knife/core/bootstrap_context.rb +1 -1
  25. data/lib/chef/knife/core/ui.rb +42 -5
  26. data/lib/chef/knife/node_run_list_add.rb +31 -2
  27. data/lib/chef/knife/ssh.rb +44 -31
  28. data/lib/chef/knife/ssl_check.rb +213 -0
  29. data/lib/chef/knife/ssl_fetch.rb +145 -0
  30. data/lib/chef/mixin/deep_merge.rb +13 -5
  31. data/lib/chef/mixin/shell_out.rb +9 -3
  32. data/lib/chef/node.rb +23 -4
  33. data/lib/chef/node/immutable_collections.rb +32 -0
  34. data/lib/chef/platform/provider_mapping.rb +21 -18
  35. data/lib/chef/platform/query_helpers.rb +10 -2
  36. data/lib/chef/policy_builder/expand_node_object.rb +3 -6
  37. data/lib/chef/provider/cron.rb +25 -3
  38. data/lib/chef/provider/mount/mount.rb +1 -1
  39. data/lib/chef/provider/package/dpkg.rb +2 -1
  40. data/lib/chef/provider/package/windows.rb +80 -0
  41. data/lib/chef/provider/package/windows/msi.rb +69 -0
  42. data/lib/chef/provider/powershell_script.rb +19 -6
  43. data/lib/chef/provider/service/solaris.rb +11 -7
  44. data/lib/chef/resource.rb +18 -5
  45. data/lib/chef/resource/conditional.rb +20 -7
  46. data/lib/chef/resource/cron.rb +18 -2
  47. data/lib/chef/resource/execute.rb +0 -2
  48. data/lib/chef/resource/powershell_script.rb +23 -1
  49. data/lib/chef/resource/script.rb +25 -0
  50. data/lib/chef/resource/subversion.rb +4 -0
  51. data/lib/chef/resource/windows_package.rb +79 -0
  52. data/lib/chef/resource/windows_script.rb +0 -5
  53. data/lib/chef/resources.rb +1 -0
  54. data/lib/chef/rest.rb +6 -1
  55. data/lib/chef/run_context.rb +22 -2
  56. data/lib/chef/run_context/cookbook_compiler.rb +12 -0
  57. data/lib/chef/util/editor.rb +92 -0
  58. data/lib/chef/util/file_edit.rb +22 -54
  59. data/lib/chef/version.rb +2 -2
  60. data/lib/chef/win32/api/installer.rb +166 -0
  61. data/lib/chef/win32/version.rb +8 -0
  62. data/spec/data/standalone_cookbook/Gemfile +1 -0
  63. data/spec/data/standalone_cookbook/chefignore +9 -0
  64. data/spec/data/standalone_cookbook/recipes/default.rb +3 -0
  65. data/spec/data/standalone_cookbook/vendor/bundle/ruby/2.0.0/gems/multi_json-1.9.0/lib/multi_json.rb +1 -0
  66. data/spec/functional/resource/powershell_spec.rb +262 -1
  67. data/spec/functional/win32/versions_spec.rb +3 -3
  68. data/spec/integration/knife/chefignore_spec.rb +1 -2
  69. data/spec/integration/knife/raw_spec.rb +8 -13
  70. data/spec/integration/knife/redirection_spec.rb +6 -14
  71. data/spec/integration/solo/solo_spec.rb +19 -0
  72. data/spec/support/shared/functional/windows_script.rb +1 -1
  73. data/spec/support/shared/integration/app_server_support.rb +42 -0
  74. data/spec/support/shared/integration/integration_helper.rb +1 -0
  75. data/spec/support/shared/unit/script_resource.rb +38 -0
  76. data/spec/unit/api_client/registration_spec.rb +109 -38
  77. data/spec/unit/application/client_spec.rb +48 -1
  78. data/spec/unit/cookbook/chefignore_spec.rb +10 -0
  79. data/spec/unit/cookbook/metadata_spec.rb +45 -1
  80. data/spec/unit/cookbook/syntax_check_spec.rb +28 -0
  81. data/spec/unit/cookbook_spec.rb +0 -10
  82. data/spec/unit/guard_interpreter/resource_guard_interpreter_spec.rb +56 -0
  83. data/spec/unit/http/simple_spec.rb +32 -0
  84. data/spec/unit/http/validate_content_length_spec.rb +187 -0
  85. data/spec/unit/knife/bootstrap_spec.rb +13 -4
  86. data/spec/unit/knife/client_bulk_delete_spec.rb +123 -38
  87. data/spec/unit/knife/client_delete_spec.rb +4 -4
  88. data/spec/unit/knife/cookbook_upload_spec.rb +181 -88
  89. data/spec/unit/knife/core/bootstrap_context_spec.rb +11 -1
  90. data/spec/unit/knife/core/ui_spec.rb +109 -38
  91. data/spec/unit/knife/node_run_list_add_spec.rb +24 -1
  92. data/spec/unit/knife/ssh_spec.rb +17 -6
  93. data/spec/unit/knife/ssl_check_spec.rb +187 -0
  94. data/spec/unit/knife/ssl_fetch_spec.rb +151 -0
  95. data/spec/unit/mixin/deep_merge_spec.rb +17 -0
  96. data/spec/unit/node/immutable_collections_spec.rb +55 -0
  97. data/spec/unit/node_spec.rb +9 -0
  98. data/spec/unit/platform/query_helpers_spec.rb +32 -0
  99. data/spec/unit/platform_spec.rb +193 -175
  100. data/spec/unit/policy_builder/expand_node_object_spec.rb +1 -1
  101. data/spec/unit/provider/cron_spec.rb +175 -1
  102. data/spec/unit/provider/mount/mount_spec.rb +33 -3
  103. data/spec/unit/provider/package/dpkg_spec.rb +4 -0
  104. data/spec/unit/provider/package/windows/msi_spec.rb +60 -0
  105. data/spec/unit/provider/package/windows_spec.rb +80 -0
  106. data/spec/unit/provider/service/macosx_spec.rb +3 -3
  107. data/spec/unit/provider/service/solaris_smf_service_spec.rb +35 -10
  108. data/spec/unit/pure_application_spec.rb +32 -0
  109. data/spec/unit/recipe_spec.rb +4 -0
  110. data/spec/unit/resource/conditional_spec.rb +13 -12
  111. data/spec/unit/resource/cron_spec.rb +7 -2
  112. data/spec/unit/resource/powershell_spec.rb +85 -2
  113. data/spec/unit/resource/subversion_spec.rb +5 -0
  114. data/spec/unit/resource/windows_package_spec.rb +74 -0
  115. data/spec/unit/resource_spec.rb +23 -1
  116. data/spec/unit/rest_spec.rb +15 -0
  117. data/spec/unit/run_context/cookbook_compiler_spec.rb +12 -0
  118. data/spec/unit/run_context_spec.rb +7 -0
  119. data/spec/unit/util/editor_spec.rb +152 -0
  120. data/spec/unit/util/file_edit_spec.rb +37 -1
  121. metadata +41 -30
@@ -22,7 +22,7 @@ if Chef::Platform.windows?
22
22
  require 'ruby-wmi'
23
23
  end
24
24
 
25
- describe "Chef::ReservedNames::Win32::Version", :windows_only do
25
+ describe "Chef::ReservedNames::Win32::Version", :windows_only, :not_supported_on_win2k3 do
26
26
  before do
27
27
 
28
28
  host = WMI::Win32_OperatingSystem.find(:first)
@@ -57,7 +57,7 @@ describe "Chef::ReservedNames::Win32::Version", :windows_only do
57
57
  end
58
58
  end
59
59
  end
60
-
60
+
61
61
  context "Win32 version object" do
62
62
  it "should have have one method for each marketing version" do
63
63
  versions = 0
@@ -88,7 +88,7 @@ describe "Chef::ReservedNames::Win32::Version", :windows_only do
88
88
  for_each_windows_version { |method_name| @version.send(method_name.to_sym) }
89
89
  end
90
90
  end
91
-
91
+
92
92
  context "Windows Operating System version" do
93
93
  it "should match the version from WMI" do
94
94
  @current_os_version.should include(@version.marketing_name)
@@ -38,14 +38,13 @@ describe 'chefignore tests' do
38
38
  file 'data_bags/bag1/chefignore', chefignore
39
39
  file 'cookbooks/cookbook1/chefignore', chefignore
40
40
 
41
- it 'nothing is ignored' do
41
+ it 'matching files and directories get ignored' do
42
42
  # NOTE: many of the "chefignore" files should probably not show up
43
43
  # themselves, but we have other tests that talk about that
44
44
  knife('list --local -Rfp /').should_succeed <<EOM
45
45
  /cookbooks/
46
46
  /cookbooks/cookbook1/
47
47
  /cookbooks/cookbook1/chefignore
48
- /cookbooks/cookbook1/x.json
49
48
  /data_bags/
50
49
  /data_bags/bag1/
51
50
  /data_bags/bag1/x.json
@@ -22,6 +22,7 @@ require 'chef/knife/show'
22
22
  describe 'knife raw' do
23
23
  extend IntegrationSupport
24
24
  include KnifeSupport
25
+ include AppServerSupport
25
26
 
26
27
  when_the_chef_server "has one of each thing" do
27
28
  client 'x', '{}'
@@ -55,7 +56,7 @@ EOM
55
56
  end
56
57
 
57
58
  it 'knife raw /blarghle returns 404' do
58
- knife('raw /blarghle').should_fail(/ERROR: Server responded with error 404 "Not Found"/)
59
+ knife('raw /blarghle').should_fail(/ERROR: Server responded with error 404 "Not Found\s*"/)
59
60
  end
60
61
 
61
62
  it 'knife raw -m DELETE /roles/x succeeds', :pending => (RUBY_VERSION < "1.9") do
@@ -165,19 +166,16 @@ EOM
165
166
 
166
167
  context 'When a server returns raw json' do
167
168
  before :each do
168
- @real_chef_server_url = Chef::Config.chef_server_url
169
169
  Chef::Config.chef_server_url = "http://127.0.0.1:9018"
170
170
  app = lambda do |env|
171
171
  [200, {'Content-Type' => 'application/json' }, ['{ "x": "y", "a": "b" }'] ]
172
172
  end
173
- @raw_server = Puma::Server.new(app, Puma::Events.new(STDERR, STDOUT))
174
- @raw_server.add_tcp_listener("127.0.0.1", 9018)
175
- @raw_server.run
173
+ @raw_server, @raw_server_thread = start_app_server(app, 9018)
176
174
  end
177
175
 
178
176
  after :each do
179
- Chef::Config.chef_server_url = @real_chef_server_url
180
- @raw_server.stop(true)
177
+ @raw_server.shutdown if @raw_server
178
+ @raw_server_thread.kill if @raw_server_thread
181
179
  end
182
180
 
183
181
  it 'knife raw /blah returns the prettified json', :pending => (RUBY_VERSION < "1.9") do
@@ -198,19 +196,16 @@ EOM
198
196
 
199
197
  context 'When a server returns text' do
200
198
  before :each do
201
- @real_chef_server_url = Chef::Config.chef_server_url
202
199
  Chef::Config.chef_server_url = "http://127.0.0.1:9018"
203
200
  app = lambda do |env|
204
201
  [200, {'Content-Type' => 'text' }, ['{ "x": "y", "a": "b" }'] ]
205
202
  end
206
- @raw_server = Puma::Server.new(app, Puma::Events.new(STDERR, STDOUT))
207
- @raw_server.add_tcp_listener("127.0.0.1", 9018)
208
- @raw_server.run
203
+ @raw_server, @raw_server_thread = start_app_server(app, 9018)
209
204
  end
210
205
 
211
206
  after :each do
212
- Chef::Config.chef_server_url = @real_chef_server_url
213
- @raw_server.stop(true)
207
+ @raw_server.shutdown if @raw_server
208
+ @raw_server_thread.kill if @raw_server_thread
214
209
  end
215
210
 
216
211
  it 'knife raw /blah returns the raw text' do
@@ -15,38 +15,30 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
- require 'puma'
19
18
  require 'support/shared/integration/integration_helper'
20
19
  require 'chef/knife/list'
21
20
 
22
21
  describe 'redirection' do
23
22
  extend IntegrationSupport
24
23
  include KnifeSupport
24
+ include AppServerSupport
25
25
 
26
26
  when_the_chef_server 'has a role' do
27
27
  role 'x', {}
28
28
 
29
29
  context 'and another server redirects to it with 302' do
30
30
  before :each do
31
- @real_chef_server_url = Chef::Config.chef_server_url
31
+ real_chef_server_url = Chef::Config.chef_server_url
32
32
  Chef::Config.chef_server_url = "http://127.0.0.1:9018"
33
33
  app = lambda do |env|
34
- [302, {'Content-Type' => 'text','Location' => "#{@real_chef_server_url}#{env['PATH_INFO']}" }, ['302 found'] ]
35
- end
36
- @redirector_server = Puma::Server.new(app, Puma::Events.new(STDERR, STDOUT))
37
- @redirector_server.add_tcp_listener("127.0.0.1", 9018)
38
- @redirector_server.run
39
- Timeout::timeout(5) do
40
- until @redirector_server.running
41
- sleep(0.01)
42
- end
43
- raise @server_error if @server_error
34
+ [302, {'Content-Type' => 'text','Location' => "#{real_chef_server_url}#{env['PATH_INFO']}" }, ['302 found'] ]
44
35
  end
36
+ @redirector_server, @redirector_server_thread = start_app_server(app, 9018)
45
37
  end
46
38
 
47
39
  after :each do
48
- Chef::Config.chef_server_url = @real_chef_server_url
49
- @redirector_server.stop(true)
40
+ @redirector_server.shutdown if @redirector_server
41
+ @redirector_thread.kill if @redirector_thread
50
42
  end
51
43
 
52
44
  it 'knife list /roles returns the role' do
@@ -42,6 +42,25 @@ E
42
42
 
43
43
  end
44
44
 
45
+ when_the_repository "has a cookbook with an undeclared dependency" do
46
+ file 'cookbooks/x/metadata.rb', 'version "1.0.0"'
47
+ file 'cookbooks/x/recipes/default.rb', 'include_recipe "ancient::aliens"'
48
+
49
+ file 'cookbooks/ancient/metadata.rb', 'version "1.0.0"'
50
+ file 'cookbooks/ancient/recipes/aliens.rb', 'print "it was aliens"'
51
+
52
+ it "should exit with an error" do
53
+ file 'config/solo.rb', <<EOM
54
+ cookbook_path "#{path_to('cookbooks')}"
55
+ file_cache_path "#{path_to('config/cache')}"
56
+ EOM
57
+ result = shell_out("ruby bin/chef-solo -c \"#{path_to('config/solo.rb')}\" -o 'x::default' -l debug", :cwd => chef_dir)
58
+ result.exitstatus.should == 0 # For CHEF-5120 this becomes 1
59
+ result.stdout.should include("WARN: MissingCookbookDependency")
60
+ end
61
+ end
62
+
63
+
45
64
  when_the_repository "has a cookbook with a recipe with sleep" do
46
65
  directory 'logs'
47
66
  file 'logs/runs.log', ''
@@ -38,7 +38,7 @@ shared_context Chef::Resource::WindowsScript do
38
38
  end
39
39
 
40
40
  before(:each) do
41
- k File.delete(script_output_path) if File.exists?(script_output_path)
41
+ File.delete(script_output_path) if File.exists?(script_output_path)
42
42
  end
43
43
 
44
44
  after(:each) do
@@ -0,0 +1,42 @@
1
+ #
2
+ # Author:: John Keiser (<jkeiser@opscode.com>)
3
+ # Author:: Ho-Sheng Hsiao (<hosh@opscode.com>)
4
+ # Copyright:: Copyright (c) 2012, 2013 Opscode, Inc.
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ require 'rack'
21
+ require 'stringio'
22
+
23
+ module AppServerSupport
24
+ def start_app_server(app, port)
25
+ server = nil
26
+ thread = Thread.new do
27
+ Rack::Handler::WEBrick.run(app,
28
+ :Port => 9018,
29
+ :AccessLog => [],
30
+ :Logger => WEBrick::Log::new(StringIO.new, 7)
31
+ ) do |found_server|
32
+ server = found_server
33
+ end
34
+ end
35
+ Timeout::timeout(5) do
36
+ until server && server.status == :Running
37
+ sleep(0.01)
38
+ end
39
+ end
40
+ [server, thread]
41
+ end
42
+ end
@@ -23,6 +23,7 @@ require 'chef/config'
23
23
  require 'chef_zero/rspec'
24
24
  require 'json'
25
25
  require 'support/shared/integration/knife_support'
26
+ require 'support/shared/integration/app_server_support'
26
27
  require 'spec_helper'
27
28
 
28
29
  module IntegrationSupport
@@ -48,5 +48,43 @@ shared_examples_for "a script resource" do
48
48
  @resource.flags.should eql("-f")
49
49
  end
50
50
 
51
+ describe "when executing guards" do
52
+ let(:resource) { @resource }
53
+
54
+ before(:each) do
55
+ node = Chef::Node.new
56
+
57
+ node.automatic[:platform] = "debian"
58
+ node.automatic[:platform_version] = "6.0"
59
+
60
+ events = Chef::EventDispatch::Dispatcher.new
61
+ run_context = Chef::RunContext.new(node, {}, events)
62
+ resource.run_context = run_context
63
+ resource.code 'echo hi'
64
+ end
65
+
66
+ it "inherits exactly the :cwd, :environment, :group, :path, :user, and :umask attributes from a parent resource class" do
67
+ inherited_difference = Chef::Resource::Script.guard_inherited_attributes -
68
+ [:cwd, :environment, :group, :path, :user, :umask ]
69
+
70
+ inherited_difference.should == []
71
+ end
72
+
73
+ it "when guard_interpreter is set to the default value, the guard command string should be evaluated by command execution and not through a resource" do
74
+ Chef::Resource::Conditional.any_instance.should_not_receive(:evaluate_block)
75
+ Chef::Resource::Conditional.any_instance.should_receive(:evaluate_command).and_return(true)
76
+ Chef::GuardInterpreter::ResourceGuardInterpreter.any_instance.should_not_receive(:evaluate_action)
77
+ resource.only_if 'echo hi'
78
+ resource.should_skip?(:run).should == nil
79
+ end
80
+
81
+ it "when a valid guard_interpreter resource is specified, a block should be used to evaluate the guard" do
82
+ Chef::GuardInterpreter::DefaultGuardInterpreter.any_instance.should_not_receive(:evaluate)
83
+ Chef::GuardInterpreter::ResourceGuardInterpreter.any_instance.should_receive(:evaluate_action).and_return(true)
84
+ resource.guard_interpreter :script
85
+ resource.only_if 'echo hi'
86
+ resource.should_skip?(:run).should == nil
87
+ end
88
+ end
51
89
  end
52
90
 
@@ -22,16 +22,45 @@ require 'tempfile'
22
22
  require 'chef/api_client/registration'
23
23
 
24
24
  describe Chef::ApiClient::Registration do
25
+
25
26
  let(:key_location) do
26
27
  make_tmpname("client-registration-key")
27
28
  end
28
29
 
29
- let(:registration) { Chef::ApiClient::Registration.new("silent-bob", key_location) }
30
+ let(:client_name) { "silent-bob" }
31
+
32
+ subject(:registration) { Chef::ApiClient::Registration.new(client_name, key_location) }
30
33
 
31
- let :private_key_data do
34
+ let(:private_key_data) do
32
35
  File.open(Chef::Config[:validation_key], "r") {|f| f.read.chomp }
33
36
  end
34
37
 
38
+ let(:http_mock) { double("Chef::REST mock") }
39
+
40
+ let(:expected_post_data) do
41
+ { :name => client_name, :admin => false }
42
+ end
43
+
44
+ let(:expected_put_data) do
45
+ { :name => client_name, :admin => false, :private_key => true }
46
+ end
47
+
48
+ let(:server_v10_response) do
49
+ {"uri" => "https://chef.local/clients/#{client_name}",
50
+ "private_key" => "--begin rsa key etc--"}
51
+ end
52
+
53
+ # Server v11 includes `json_class` on all replies
54
+ let(:server_v11_response) do
55
+ response = Chef::ApiClient.new
56
+ response.name(client_name)
57
+ response.private_key("--begin rsa key etc--")
58
+ response
59
+ end
60
+
61
+ let(:response_409) { Net::HTTPConflict.new("1.1", "409", "Conflict") }
62
+ let(:exception_409) { Net::HTTPServerException.new("409 conflict", response_409) }
63
+
35
64
  before do
36
65
  Chef::Config[:validation_client_name] = "test-validator"
37
66
  Chef::Config[:validation_key] = File.expand_path('ssl/private_key.pem', CHEF_SPEC_DATA)
@@ -39,8 +68,6 @@ describe Chef::ApiClient::Registration do
39
68
 
40
69
  after do
41
70
  File.unlink(key_location) if File.exist?(key_location)
42
- Chef::Config[:validation_client_name] = nil
43
- Chef::Config[:validation_key] = nil
44
71
  end
45
72
 
46
73
  it "has an HTTP client configured with validator credentials" do
@@ -50,57 +77,107 @@ describe Chef::ApiClient::Registration do
50
77
  end
51
78
 
52
79
  describe "when creating/updating the client on the server" do
53
- let(:http_mock) { double("Chef::REST mock") }
54
-
55
80
  before do
56
81
  registration.stub(:http_api).and_return(http_mock)
57
82
  end
58
83
 
59
84
  it "creates a new ApiClient on the server using the validator identity" do
60
- response = {"uri" => "https://chef.local/clients/silent-bob",
61
- "private_key" => "--begin rsa key etc--"}
62
85
  http_mock.should_receive(:post).
63
- with("clients", :name => 'silent-bob', :admin => false).
64
- and_return(response)
65
- registration.create_or_update.should == response
86
+ with("clients", expected_post_data).
87
+ and_return(server_v10_response)
88
+ registration.create_or_update.should == server_v10_response
66
89
  registration.private_key.should == "--begin rsa key etc--"
67
90
  end
68
91
 
69
92
  context "and the client already exists on a Chef 10 server" do
70
93
  it "requests a new key from the server and saves it" do
71
- response = {"name" => "silent-bob", "private_key" => "--begin rsa key etc--" }
72
-
73
- response_409 = Net::HTTPConflict.new("1.1", "409", "Conflict")
74
- exception_409 = Net::HTTPServerException.new("409 conflict", response_409)
75
-
76
- http_mock.should_receive(:post).and_raise(exception_409)
94
+ http_mock.should_receive(:post).with("clients", expected_post_data).
95
+ and_raise(exception_409)
77
96
  http_mock.should_receive(:put).
78
- with("clients/silent-bob", :name => 'silent-bob', :admin => false, :private_key => true).
79
- and_return(response)
80
- registration.create_or_update.should == response
97
+ with("clients/#{client_name}", expected_put_data).
98
+ and_return(server_v10_response)
99
+ registration.create_or_update.should == server_v10_response
81
100
  registration.private_key.should == "--begin rsa key etc--"
82
101
  end
83
102
  end
84
103
 
85
104
  context "and the client already exists on a Chef 11 server" do
86
105
  it "requests a new key from the server and saves it" do
87
- response = Chef::ApiClient.new
88
- response.name("silent-bob")
89
- response.private_key("--begin rsa key etc--")
90
-
91
- response_409 = Net::HTTPConflict.new("1.1", "409", "Conflict")
92
- exception_409 = Net::HTTPServerException.new("409 conflict", response_409)
93
-
94
106
  http_mock.should_receive(:post).and_raise(exception_409)
95
107
  http_mock.should_receive(:put).
96
- with("clients/silent-bob", :name => 'silent-bob', :admin => false, :private_key => true).
97
- and_return(response)
98
- registration.create_or_update.should == response
108
+ with("clients/#{client_name}", expected_put_data).
109
+ and_return(server_v11_response)
110
+ registration.create_or_update.should == server_v11_response
99
111
  registration.private_key.should == "--begin rsa key etc--"
100
112
  end
101
113
  end
102
114
  end
103
115
 
116
+ context "when local key generation is enabled", :nofocus do
117
+ let(:generated_private_key_pem) { IO.read(File.expand_path('ssl/private_key.pem', CHEF_SPEC_DATA)) }
118
+ let(:generated_private_key) { OpenSSL::PKey::RSA.new(generated_private_key_pem) }
119
+ let(:generated_public_key) { generated_private_key.public_key }
120
+
121
+ let(:expected_post_data) do
122
+ { :name => client_name, :admin => false, :public_key => generated_public_key.to_pem }
123
+ end
124
+
125
+ let(:expected_put_data) do
126
+ { :name => client_name, :admin => false, :public_key => generated_public_key.to_pem }
127
+ end
128
+
129
+ let(:create_with_pkey_response) do
130
+ {
131
+ "uri" => "",
132
+ "public_key" => generated_public_key.to_pem
133
+ }
134
+ end
135
+
136
+ let(:update_with_pkey_response) do
137
+ {"name"=>client_name,
138
+ "admin"=>false,
139
+ "public_key"=> generated_public_key,
140
+ "validator"=>false,
141
+ "private_key"=>false,
142
+ "clientname"=>client_name}
143
+ end
144
+
145
+
146
+ before do
147
+ registration.stub(:http_api).and_return(http_mock)
148
+ Chef::Config.local_key_generation = true
149
+ OpenSSL::PKey::RSA.should_receive(:generate).with(2048).and_return(generated_private_key)
150
+ end
151
+
152
+ it "posts a locally generated public key to the server to create a client" do
153
+ http_mock.should_receive(:post).
154
+ with("clients", expected_post_data).
155
+ and_return(create_with_pkey_response)
156
+ registration.create_or_update.should == create_with_pkey_response
157
+ registration.private_key.should == generated_private_key_pem
158
+ end
159
+
160
+ it "puts a locally generated public key to the server to update a client" do
161
+ http_mock.should_receive(:post).
162
+ with("clients", expected_post_data).
163
+ and_raise(exception_409)
164
+ http_mock.should_receive(:put).
165
+ with("clients/#{client_name}", expected_put_data).
166
+ and_return(update_with_pkey_response)
167
+ registration.create_or_update.should == update_with_pkey_response
168
+ registration.private_key.should == generated_private_key_pem
169
+ end
170
+
171
+ it "writes the generated private key to disk" do
172
+ http_mock.should_receive(:post).
173
+ with("clients", expected_post_data).
174
+ and_return(create_with_pkey_response)
175
+ registration.run
176
+ IO.read(key_location).should == generated_private_key_pem
177
+ end
178
+
179
+ end
180
+
104
181
  describe "when writing the private key to disk" do
105
182
  before do
106
183
  registration.stub(:private_key).and_return('--begin rsa key etc--')
@@ -125,16 +202,12 @@ describe Chef::ApiClient::Registration do
125
202
 
126
203
  describe "when registering a client" do
127
204
 
128
- let(:http_mock) { double("Chef::REST mock") }
129
-
130
205
  before do
131
206
  registration.stub(:http_api).and_return(http_mock)
132
207
  end
133
208
 
134
209
  it "creates the client on the server and writes the key" do
135
- response = {"uri" => "http://chef.local/clients/silent-bob",
136
- "private_key" => "--begin rsa key etc--" }
137
- http_mock.should_receive(:post).ordered.and_return(response)
210
+ http_mock.should_receive(:post).ordered.and_return(server_v10_response)
138
211
  registration.run
139
212
  IO.read(key_location).should == "--begin rsa key etc--"
140
213
  end
@@ -149,9 +222,7 @@ describe Chef::ApiClient::Registration do
149
222
  http_mock.should_receive(:post).ordered.and_raise(exception_500) # 4
150
223
  http_mock.should_receive(:post).ordered.and_raise(exception_500) # 5
151
224
 
152
- response = {"uri" => "http://chef.local/clients/silent-bob",
153
- "private_key" => "--begin rsa key etc--" }
154
- http_mock.should_receive(:post).ordered.and_return(response)
225
+ http_mock.should_receive(:post).ordered.and_return(server_v10_response)
155
226
  registration.run
156
227
  IO.read(key_location).should == "--begin rsa key etc--"
157
228
  end