chef 10.16.6 → 10.18.0.rc.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. data/distro/common/html/chef-client.8.html +4 -4
  2. data/distro/common/html/chef-expander.8.html +4 -4
  3. data/distro/common/html/chef-expanderctl.8.html +4 -4
  4. data/distro/common/html/chef-server-webui.8.html +4 -4
  5. data/distro/common/html/chef-server.8.html +4 -4
  6. data/distro/common/html/chef-solo.8.html +4 -4
  7. data/distro/common/html/chef-solr.8.html +4 -4
  8. data/distro/common/html/knife-bootstrap.1.html +4 -4
  9. data/distro/common/html/knife-client.1.html +4 -4
  10. data/distro/common/html/knife-configure.1.html +4 -4
  11. data/distro/common/html/knife-cookbook-site.1.html +4 -4
  12. data/distro/common/html/knife-cookbook.1.html +4 -4
  13. data/distro/common/html/knife-data-bag.1.html +4 -4
  14. data/distro/common/html/knife-environment.1.html +4 -4
  15. data/distro/common/html/knife-exec.1.html +4 -4
  16. data/distro/common/html/knife-index.1.html +4 -4
  17. data/distro/common/html/knife-node.1.html +4 -4
  18. data/distro/common/html/knife-role.1.html +4 -4
  19. data/distro/common/html/knife-search.1.html +4 -4
  20. data/distro/common/html/knife-ssh.1.html +4 -4
  21. data/distro/common/html/knife-status.1.html +4 -4
  22. data/distro/common/html/knife-tag.1.html +4 -4
  23. data/distro/common/html/knife.1.html +4 -4
  24. data/distro/common/html/shef.1.html +4 -4
  25. data/distro/common/man/man1/knife-bootstrap.1 +1 -1
  26. data/distro/common/man/man1/knife-client.1 +1 -1
  27. data/distro/common/man/man1/knife-configure.1 +1 -1
  28. data/distro/common/man/man1/knife-cookbook-site.1 +1 -1
  29. data/distro/common/man/man1/knife-cookbook.1 +1 -1
  30. data/distro/common/man/man1/knife-data-bag.1 +1 -1
  31. data/distro/common/man/man1/knife-environment.1 +1 -1
  32. data/distro/common/man/man1/knife-exec.1 +1 -1
  33. data/distro/common/man/man1/knife-index.1 +1 -1
  34. data/distro/common/man/man1/knife-node.1 +1 -1
  35. data/distro/common/man/man1/knife-role.1 +1 -1
  36. data/distro/common/man/man1/knife-search.1 +1 -1
  37. data/distro/common/man/man1/knife-ssh.1 +1 -1
  38. data/distro/common/man/man1/knife-status.1 +1 -1
  39. data/distro/common/man/man1/knife-tag.1 +1 -1
  40. data/distro/common/man/man1/knife.1 +1 -1
  41. data/distro/common/man/man1/shef.1 +1 -1
  42. data/distro/common/man/man8/chef-client.8 +1 -1
  43. data/distro/common/man/man8/chef-expander.8 +1 -1
  44. data/distro/common/man/man8/chef-expanderctl.8 +1 -1
  45. data/distro/common/man/man8/chef-server-webui.8 +1 -1
  46. data/distro/common/man/man8/chef-server.8 +1 -1
  47. data/distro/common/man/man8/chef-solo.8 +1 -1
  48. data/distro/common/man/man8/chef-solr.8 +1 -1
  49. data/lib/chef/api_client.rb +22 -0
  50. data/lib/chef/cookbook/chefignore.rb +1 -1
  51. data/lib/chef/cookbook/cookbook_version_loader.rb +1 -3
  52. data/lib/chef/encrypted_data_bag_item.rb +135 -6
  53. data/lib/chef/formatters/doc.rb +2 -2
  54. data/lib/chef/formatters/error_inspectors/resource_failure_inspector.rb +1 -0
  55. data/lib/chef/knife/bootstrap/archlinux-gems.erb +6 -19
  56. data/lib/chef/knife/bootstrap/centos5-gems.erb +15 -24
  57. data/lib/chef/knife/bootstrap/chef-full.erb +9 -22
  58. data/lib/chef/knife/bootstrap/fedora13-gems.erb +5 -19
  59. data/lib/chef/knife/bootstrap/ubuntu10.04-apt.erb +4 -16
  60. data/lib/chef/knife/bootstrap/ubuntu10.04-gems.erb +7 -24
  61. data/lib/chef/knife/bootstrap/ubuntu12.04-gems.erb +5 -19
  62. data/lib/chef/knife/bootstrap.rb +3 -3
  63. data/lib/chef/knife/client_reregister.rb +5 -4
  64. data/lib/chef/knife/cookbook_create.rb +178 -28
  65. data/lib/chef/knife/cookbook_site_install.rb +1 -1
  66. data/lib/chef/knife/core/bootstrap_context.rb +2 -2
  67. data/lib/chef/knife/ssh.rb +31 -15
  68. data/lib/chef/mixin/recipe_definition_dsl_core.rb +1 -1
  69. data/lib/chef/platform.rb +8 -0
  70. data/lib/chef/provider/log.rb +1 -1
  71. data/lib/chef/provider/package/yum-dump.py +20 -0
  72. data/lib/chef/provider/package/yum.rb +41 -0
  73. data/lib/chef/resource/log.rb +10 -1
  74. data/lib/chef/resource.rb +3 -2
  75. data/lib/chef/rest.rb +10 -5
  76. data/lib/chef/version.rb +1 -1
  77. data/spec/data/cookbooks/chefignore +2 -0
  78. data/spec/functional/knife/ssh_spec.rb +59 -1
  79. data/spec/stress/win32/security_spec.rb +4 -4
  80. data/spec/support/matchers/leak.rb +1 -1
  81. data/spec/unit/api_client_spec.rb +90 -17
  82. data/spec/unit/cookbook/chefignore_spec.rb +2 -1
  83. data/spec/unit/encrypted_data_bag_item_spec.rb +177 -6
  84. data/spec/unit/formatters/error_inspectors/resource_failure_inspector_spec.rb +20 -0
  85. data/spec/unit/knife/bootstrap_spec.rb +69 -28
  86. data/spec/unit/knife/client_reregister_spec.rb +23 -22
  87. data/spec/unit/knife/cookbook_site_install_spec.rb +12 -2
  88. data/spec/unit/knife/core/bootstrap_context_spec.rb +7 -0
  89. data/spec/unit/knife/data_bag_create_spec.rb +5 -0
  90. data/spec/unit/knife/data_bag_edit_spec.rb +13 -0
  91. data/spec/unit/knife/data_bag_from_file_spec.rb +15 -1
  92. data/spec/unit/knife/ssh_spec.rb +93 -1
  93. data/spec/unit/provider/package/yum_spec.rb +79 -11
  94. data/spec/unit/resource/log_spec.rb +9 -0
  95. metadata +854 -850
@@ -23,6 +23,7 @@ describe Chef::Knife::Ssh do
23
23
 
24
24
  before(:all) do
25
25
  @original_config = Chef::Config.hash_dup
26
+ @original_knife_config = Chef::Config[:knife].dup
26
27
  Chef::Knife::Ssh.load_deps
27
28
  @server = TinyServer::Manager.new
28
29
  @server.start
@@ -30,6 +31,7 @@ describe Chef::Knife::Ssh do
30
31
 
31
32
  after(:all) do
32
33
  Chef::Config.configuration = @original_config
34
+ Chef::Config[:knife] = @original_knife_config
33
35
  @server.stop
34
36
  end
35
37
 
@@ -89,6 +91,19 @@ describe Chef::Knife::Ssh do
89
91
  end
90
92
  end
91
93
 
94
+ describe "port" do
95
+ context "when -p 31337 is provided" do
96
+ before do
97
+ setup_knife(['-p 31337', '*:*', 'uptime'])
98
+ end
99
+
100
+ it "uses the ssh_port" do
101
+ @knife.run
102
+ @knife.config[:ssh_port].should == "31337"
103
+ end
104
+ end
105
+ end
106
+
92
107
  describe "user" do
93
108
  context "when knife[:ssh_user] is set" do
94
109
  before do
@@ -192,9 +207,52 @@ describe Chef::Knife::Ssh do
192
207
  end
193
208
  end
194
209
 
210
+ describe "gateway" do
211
+ context "when knife[:ssh_gateway] is set" do
212
+ before do
213
+ setup_knife(['*:*', 'uptime'])
214
+ Chef::Config[:knife][:ssh_gateway] = "user@ec2.public_hostname"
215
+ end
216
+
217
+ it "uses the ssh_gateway" do
218
+ @knife.session.should_receive(:via).with("ec2.public_hostname", "user", {})
219
+ @knife.run
220
+ @knife.config[:ssh_gateway].should == "user@ec2.public_hostname"
221
+ end
222
+ end
223
+
224
+ context "when -G user@ec2.public_hostname is provided" do
225
+ before do
226
+ setup_knife(['-G user@ec2.public_hostname', '*:*', 'uptime'])
227
+ Chef::Config[:knife][:ssh_gateway] = nil
228
+ end
229
+
230
+ it "uses the ssh_gateway" do
231
+ @knife.session.should_receive(:via).with("ec2.public_hostname", "user", {})
232
+ @knife.run
233
+ @knife.config[:ssh_gateway].should == "user@ec2.public_hostname"
234
+ end
235
+ end
236
+
237
+ context "when the gateway requires a password" do
238
+ before do
239
+ setup_knife(['-G user@ec2.public_hostname', '*:*', 'uptime'])
240
+ Chef::Config[:knife][:ssh_gateway] = nil
241
+ @knife.session.stub(:via) do |host, user, options|
242
+ raise Net::SSH::AuthenticationFailed unless options[:password]
243
+ end
244
+ end
245
+
246
+ it "should prompt the user for a password" do
247
+ @knife.ui.should_receive(:ask).with("Enter the password for user@ec2.public_hostname: ").and_return("password")
248
+ @knife.run
249
+ end
250
+ end
251
+ end
252
+
195
253
  def setup_knife(params=[])
196
254
  @knife = Chef::Knife::Ssh.new(params)
197
- @knife.stub!(:ssh_command).and_return { [] }
255
+ @knife.stub!(:ssh_command).and_return { 0 }
198
256
  @api = TinyServer::API.instance
199
257
  @api.clear
200
258
 
@@ -56,11 +56,11 @@ describe 'Chef::ReservedNames::Win32::Security', :windows_only do
56
56
  end
57
57
 
58
58
  it "should not leak when creating a new ACL and setting it on a file" do
59
- securable_object = Security::SecurableObject.new(@monkeyfoo)
59
+ securable_object = Chef::ReservedNames::Win32::Security::SecurableObject.new(@monkeyfoo)
60
60
  lambda {
61
- securable_object.dacl = Security::ACL.create([
62
- Chef::ReservedNames::Win32::Security::ACE.access_allowed(Security::SID.Everyone, Chef::ReservedNames::Win32::API::Security::GENERIC_READ),
63
- Chef::ReservedNames::Win32::Security::ACE.access_denied(Security::SID.from_account("Users"), Chef::ReservedNames::Win32::API::Security::GENERIC_ALL)
61
+ securable_object.dacl = Chef::ReservedNames::Win32::Security::ACL.create([
62
+ Chef::ReservedNames::Win32::Security::ACE.access_allowed(Chef::ReservedNames::Win32::Security::SID.Everyone, Chef::ReservedNames::Win32::API::Security::GENERIC_READ),
63
+ Chef::ReservedNames::Win32::Security::ACE.access_denied(Chef::ReservedNames::Win32::Security::SID.from_account("Users"), Chef::ReservedNames::Win32::API::Security::GENERIC_ALL)
64
64
  ])
65
65
  GC.start
66
66
  }.should_not leak_memory(:warmup => 50, :iterations => 100)
@@ -60,7 +60,7 @@ module Matchers
60
60
  def profiler
61
61
  @profiler ||= begin
62
62
  if Chef::Platform.windows?
63
- require File.join(File.dirname(__FILE__), '..', 'prof', 'win32')
63
+ require File.join(File.dirname(__FILE__), '..', 'platforms', 'prof', 'win32')
64
64
  RSpec::Prof::Win32::Profiler.new
65
65
  else
66
66
  require File.join(File.dirname(__FILE__), '..', 'prof', 'gc')
@@ -151,33 +151,106 @@ describe Chef::ApiClient do
151
151
  end
152
152
  end
153
153
 
154
- describe "deserialize" do
154
+ describe "when deserializing from JSON" do
155
155
  before(:each) do
156
- @client.name("black")
157
- @client.public_key("crowes")
158
- @client.private_key("monkeypants")
159
- @client.admin(true)
160
- @deserial = Chef::JSONCompat.from_json(@client.to_json)
156
+ client = {
157
+ "name" => "black",
158
+ "public_key" => "crowes",
159
+ "private_key" => "monkeypants",
160
+ "admin" => true,
161
+ "json_class" => "Chef::ApiClient"
162
+ }
163
+ @client = Chef::JSONCompat.from_json(client.to_json)
161
164
  end
162
165
 
163
166
  it "should deserialize to a Chef::ApiClient object" do
164
- @deserial.should be_a_kind_of(Chef::ApiClient)
167
+ @client.should be_a_kind_of(Chef::ApiClient)
165
168
  end
166
169
 
167
- %w{
168
- name
169
- public_key
170
- admin
171
- }.each do |t|
172
- it "should match '#{t}'" do
173
- @deserial.send(t.to_sym).should == @client.send(t.to_sym)
174
- end
170
+ it "preserves the name" do
171
+ @client.name.should == "black"
175
172
  end
176
173
 
177
- it "should not include the private key" do
178
- @deserial.private_key.should == nil
174
+ it "preserves the public key" do
175
+ @client.public_key.should == "crowes"
176
+ end
177
+
178
+ it "preserves the admin status" do
179
+ @client.admin.should be_true
180
+ end
181
+
182
+ it "includes the private key if present" do
183
+ @client.private_key.should == "monkeypants"
184
+ end
185
+
186
+ end
187
+
188
+ describe "when requesting a new key" do
189
+ before do
190
+ @http_client = mock("Chef::REST mock")
191
+ Chef::REST.stub!(:new).and_return(@http_client)
192
+ end
193
+
194
+ context "and the client does not exist on the server" do
195
+ before do
196
+ @a_404_response = Net::HTTPNotFound.new("404 not found and such", nil, nil)
197
+ @a_404_exception = Net::HTTPServerException.new("404 not found exception", @a_404_response)
198
+
199
+ @http_client.should_receive(:get_rest).with("clients/lost-my-key").and_raise(@a_404_exception)
200
+ end
201
+
202
+ it "raises a 404 error" do
203
+ lambda { Chef::ApiClient.reregister("lost-my-key") }.should raise_error(Net::HTTPServerException)
204
+ end
179
205
  end
180
206
 
207
+ context "and the client exists" do
208
+ before do
209
+ @api_client_without_key = Chef::ApiClient.new
210
+ @api_client_without_key.name("lost-my-key")
211
+ @http_client.should_receive(:get_rest).with("clients/lost-my-key").and_return(@api_client_without_key)
212
+ end
213
+
214
+
215
+ context "and the client exists on a Chef 11-like server" do
216
+ before do
217
+ @api_client_with_key = Chef::ApiClient.new
218
+ @api_client_with_key.name("lost-my-key")
219
+ @api_client_with_key.private_key("the new private key")
220
+ @http_client.should_receive(:put_rest).
221
+ with("clients/lost-my-key", :name => "lost-my-key", :admin => false, :private_key => true).
222
+ and_return(@api_client_with_key)
223
+ end
224
+
225
+ it "returns an ApiClient with a private key" do
226
+ response = Chef::ApiClient.reregister("lost-my-key")
227
+ # no sane == method for ApiClient :'(
228
+ response.should == @api_client_without_key
229
+ response.private_key.should == "the new private key"
230
+ response.name.should == "lost-my-key"
231
+ response.admin.should be_false
232
+ end
233
+ end
234
+
235
+ context "and the client exists on a Chef 10-like server" do
236
+ before do
237
+ @api_client_with_key = {"name" => "lost-my-key", "private_key" => "the new private key"}
238
+ @http_client.should_receive(:put_rest).
239
+ with("clients/lost-my-key", :name => "lost-my-key", :admin => false, :private_key => true).
240
+ and_return(@api_client_with_key)
241
+ end
242
+
243
+ it "returns an ApiClient with a private key" do
244
+ response = Chef::ApiClient.reregister("lost-my-key")
245
+ # no sane == method for ApiClient :'(
246
+ response.should == @api_client_without_key
247
+ response.private_key.should == "the new private key"
248
+ response.name.should == "lost-my-key"
249
+ response.admin.should be_false
250
+ end
251
+ end
252
+
253
+ end
181
254
  end
182
255
  end
183
256
 
@@ -23,7 +23,7 @@ describe Chef::Cookbook::Chefignore do
23
23
  end
24
24
 
25
25
  it "loads the globs in the chefignore file" do
26
- @chefignore.ignores.should =~ %w[recipes/ignoreme.rb]
26
+ @chefignore.ignores.should =~ %w[recipes/ignoreme.rb ignored]
27
27
  end
28
28
 
29
29
  it "removes items from an array that match the ignores" do
@@ -32,6 +32,7 @@ describe Chef::Cookbook::Chefignore do
32
32
  end
33
33
 
34
34
  it "determines if a file is ignored" do
35
+ @chefignore.ignored?('ignored').should be_true
35
36
  @chefignore.ignored?('recipes/ignoreme.rb').should be_true
36
37
  @chefignore.ignored?('recipes/dontignoreme.rb').should be_false
37
38
  end
@@ -19,6 +19,152 @@
19
19
  require 'spec_helper'
20
20
  require 'chef/encrypted_data_bag_item'
21
21
 
22
+ module Version0Encryptor
23
+ def self.encrypt_value(plaintext_data, key)
24
+ data = plaintext_data.to_yaml
25
+
26
+ cipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
27
+ cipher.encrypt
28
+ cipher.pkcs5_keyivgen(key)
29
+ encrypted_bytes = cipher.update(data)
30
+ encrypted_bytes << cipher.final
31
+ Base64.encode64(encrypted_bytes)
32
+ end
33
+ end
34
+
35
+ # Encryption/serialization code from Chef 11.
36
+ class Version1Encryptor
37
+ ALGORITHM = "aes-256-cbc"
38
+
39
+ attr_reader :key
40
+ attr_reader :plaintext_data
41
+
42
+ # Create a new Encryptor for +data+, which will be encrypted with the given
43
+ # +key+.
44
+ #
45
+ # === Arguments:
46
+ # * data: An object of any type that can be serialized to json
47
+ # * key: A String representing the desired passphrase
48
+ # * iv: The optional +iv+ parameter is intended for testing use only. When
49
+ # *not* supplied, Encryptor will use OpenSSL to generate a secure random
50
+ # IV, which is what you want.
51
+ def initialize(plaintext_data, key, iv=nil)
52
+ @plaintext_data = plaintext_data
53
+ @key = key
54
+ @iv = iv && Base64.decode64(iv)
55
+ end
56
+
57
+ # Returns a wrapped and encrypted version of +plaintext_data+ suitable for
58
+ # using as the value in an encrypted data bag item.
59
+ def for_encrypted_item
60
+ {
61
+ "encrypted_data" => encrypted_data,
62
+ "iv" => Base64.encode64(iv),
63
+ "version" => 1,
64
+ "cipher" => ALGORITHM
65
+ }
66
+ end
67
+
68
+ # Generates or returns the IV.
69
+ def iv
70
+ # Generated IV comes from OpenSSL::Cipher::Cipher#random_iv
71
+ # This gets generated when +openssl_encryptor+ gets created.
72
+ openssl_encryptor if @iv.nil?
73
+ @iv
74
+ end
75
+
76
+ # Generates (and memoizes) an OpenSSL::Cipher::Cipher object and configures
77
+ # it for the specified iv and encryption key.
78
+ def openssl_encryptor
79
+ @openssl_encryptor ||= begin
80
+ encryptor = OpenSSL::Cipher::Cipher.new(ALGORITHM)
81
+ encryptor.encrypt
82
+ @iv ||= encryptor.random_iv
83
+ encryptor.iv = @iv
84
+ encryptor.key = Digest::SHA256.digest(key)
85
+ encryptor
86
+ end
87
+ end
88
+
89
+ # Encrypts and Base64 encodes +serialized_data+
90
+ def encrypted_data
91
+ @encrypted_data ||= begin
92
+ enc_data = openssl_encryptor.update(serialized_data)
93
+ enc_data << openssl_encryptor.final
94
+ Base64.encode64(enc_data)
95
+ end
96
+ end
97
+
98
+ # Wraps the data in a single key Hash (JSON Object) and converts to JSON.
99
+ # The wrapper is required because we accept values (such as Integers or
100
+ # Strings) that do not produce valid JSON when serialized without the
101
+ # wrapper.
102
+ def serialized_data
103
+ Chef::JSONCompat.to_json(:json_wrapper => plaintext_data)
104
+ end
105
+ end
106
+
107
+
108
+ describe Chef::EncryptedDataBagItem::Decryptor do
109
+ context "when decrypting a version 1 (JSON+aes-256-cbc+random iv) encrypted value" do
110
+ before do
111
+ @encryptor = Version1Encryptor.new({"foo" => "bar"}, "passwd")
112
+ @encrypted_value = @encryptor.for_encrypted_item
113
+
114
+ @decryptor = Chef::EncryptedDataBagItem::Decryptor.for(@encrypted_value, "passwd")
115
+ end
116
+
117
+ it "selects the correct strategy for version 1" do
118
+ @decryptor.should be_a_kind_of Chef::EncryptedDataBagItem::Decryptor::Version1Decryptor
119
+ end
120
+
121
+ it "decrypts the encrypted value" do
122
+ @decryptor.decrypted_data.should == {"json_wrapper" => {"foo" => "bar"}}.to_json
123
+ end
124
+
125
+ it "unwraps the encrypted data and returns it" do
126
+ @decryptor.for_decrypted_item.should == {"foo" => "bar"}
127
+ end
128
+
129
+ context "and the provided key is incorrect" do
130
+ before do
131
+ @decryptor = Chef::EncryptedDataBagItem::Decryptor.for(@encrypted_value, "wrong-passwd")
132
+ end
133
+
134
+ it "raises a sensible error" do
135
+ lambda { @decryptor.for_decrypted_item }.should raise_error(Chef::EncryptedDataBagItem::DecryptionFailure)
136
+ end
137
+ end
138
+
139
+ context "and the cipher is not supported" do
140
+ before do
141
+ @encrypted_value["cipher"] = "aes-256-foo"
142
+ end
143
+
144
+ it "raises a sensible error" do
145
+ lambda { @decryptor.for_decrypted_item }.should raise_error(Chef::EncryptedDataBagItem::UnsupportedCipher)
146
+ end
147
+ end
148
+
149
+ end
150
+
151
+ context "when decrypting a version 0 (YAML+aes-256-cbc+no iv) encrypted value" do
152
+ before do
153
+ @encrypted_value = Version0Encryptor.encrypt_value({"foo" => "bar"}, "passwd")
154
+
155
+ @decryptor = Chef::EncryptedDataBagItem::Decryptor.for(@encrypted_value, "passwd")
156
+ end
157
+
158
+ it "selects the correct strategy for version 0" do
159
+ @decryptor.should be_a_kind_of(Chef::EncryptedDataBagItem::Decryptor::Version0Decryptor)
160
+ end
161
+
162
+ it "decrypts the encrypted value" do
163
+ @decryptor.for_decrypted_item.should == {"foo" => "bar"}
164
+ end
165
+ end
166
+ end
167
+
22
168
  describe Chef::EncryptedDataBagItem do
23
169
  before(:each) do
24
170
  @secret = "abc123SECRET"
@@ -33,6 +179,10 @@ describe Chef::EncryptedDataBagItem do
33
179
 
34
180
  describe "encrypting" do
35
181
 
182
+ it "uses version 0 encryption/serialization" do
183
+ @enc_data["greeting"].should == Version0Encryptor.encrypt_value(@plain_data["greeting"], @secret)
184
+ end
185
+
36
186
  it "should not encrypt the 'id' key" do
37
187
  @enc_data["id"].should == "item_name"
38
188
  end
@@ -53,12 +203,7 @@ describe Chef::EncryptedDataBagItem do
53
203
  end
54
204
  end
55
205
 
56
- describe "decrypting" do
57
- before(:each) do
58
- @enc_data = Chef::EncryptedDataBagItem.encrypt_data_bag_item(@plain_data,
59
- @secret)
60
- @eh = Chef::EncryptedDataBagItem.new(@enc_data, @secret)
61
- end
206
+ shared_examples_for "a decrypted data bag item" do
62
207
 
63
208
  it "doesn't try to decrypt 'id'" do
64
209
  @eh["id"].should == @plain_data["id"]
@@ -81,6 +226,32 @@ describe Chef::EncryptedDataBagItem do
81
226
  end
82
227
  end
83
228
 
229
+ describe "decrypting" do
230
+ before(:each) do
231
+ @enc_data = Chef::EncryptedDataBagItem.encrypt_data_bag_item(@plain_data,
232
+ @secret)
233
+ @eh = Chef::EncryptedDataBagItem.new(@enc_data, @secret)
234
+ end
235
+
236
+ it_behaves_like "a decrypted data bag item"
237
+ end
238
+
239
+ describe "when decrypting a version 1 (Chef 11.x) data bag item" do
240
+ before do
241
+ @enc_data = @plain_data.inject({}) do |encrypted, (key, value)|
242
+ if key == "id"
243
+ encrypted["id"] = value
244
+ else
245
+ encrypted[key] = Version1Encryptor.new(value, @secret).for_encrypted_item
246
+ end
247
+ encrypted
248
+ end
249
+ @eh = Chef::EncryptedDataBagItem.new(@enc_data, @secret)
250
+ end
251
+
252
+ it_behaves_like "a decrypted data bag item"
253
+ end
254
+
84
255
  describe "loading" do
85
256
  it "should defer to Chef::DataBagItem.load" do
86
257
  Chef::DataBagItem.stub(:load).with(:the_bag, "my_codes").and_return(@enc_data)
@@ -112,6 +112,7 @@ describe Chef::Formatters::ErrorInspectors::ResourceFailureInspector do
112
112
  # fake code to run through #recipe_snippet
113
113
  source_file = [ "if true", "var = non_existant", "end" ]
114
114
  IO.stub!(:readlines).and_return(source_file)
115
+ File.stub!(:exists?).and_return(true)
115
116
  end
116
117
 
117
118
  it "parses a Windows path" do
@@ -127,6 +128,25 @@ describe Chef::Formatters::ErrorInspectors::ResourceFailureInspector do
127
128
  @inspector = Chef::Formatters::ErrorInspectors::ResourceFailureInspector.new(@resource, :create, @exception)
128
129
  @inspector.recipe_snippet.should match(/^# In \/home\/btm/)
129
130
  end
131
+
132
+ context "when the recipe file does not exist" do
133
+ before do
134
+ File.stub!(:exists?).and_return(false)
135
+ IO.stub!(:readlines).and_raise(Errno::ENOENT)
136
+ end
137
+
138
+ it "does not try to parse a recipe in chef-shell/irb (CHEF-3411)" do
139
+ @resource.source_line = "(irb#1):1:in `irb_binding'"
140
+ @inspector = Chef::Formatters::ErrorInspectors::ResourceFailureInspector.new(@resource, :create, @exception)
141
+ @inspector.recipe_snippet.should be_nil
142
+ end
143
+
144
+ it "does not raise an exception trying to load a non-existant file (CHEF-3411)" do
145
+ @resource.source_line = "/somewhere/in/space"
146
+ @inspector = Chef::Formatters::ErrorInspectors::ResourceFailureInspector.new(@resource, :create, @exception)
147
+ lambda { @inspector.recipe_snippet }.should_not raise_error
148
+ end
149
+ end
130
150
  end
131
151
 
132
152
  describe "when examining a resource that confuses the parser" do
@@ -132,36 +132,77 @@ describe Chef::Knife::Bootstrap do
132
132
  @knife.name_args.first.should == "barf"
133
133
  end
134
134
 
135
- describe "when configuring the underlying knife ssh command" do
136
- before do
137
- @knife.name_args = ["foo.example.com"]
138
- @knife.config[:ssh_user] = "rooty"
139
- @knife.config[:ssh_password] = "open_sesame"
140
- Chef::Config[:knife][:ssh_port] = "4001"
141
- @knife.config[:identity_file] = "~/.ssh/me.rsa"
142
- @knife.stub!(:read_template).and_return("")
143
- @knife_ssh = @knife.knife_ssh
144
- end
145
-
146
- it "configures the hostname" do
147
- @knife_ssh.name_args.first.should == "foo.example.com"
135
+ describe "when configuring the underlying knife ssh command"
136
+ context "from the command line" do
137
+ before do
138
+ @knife.name_args = ["foo.example.com"]
139
+ @knife.config[:ssh_user] = "rooty"
140
+ @knife.config[:ssh_port] = "4001"
141
+ @knife.config[:ssh_password] = "open_sesame"
142
+ Chef::Config[:knife][:ssh_user] = nil
143
+ Chef::Config[:knife][:ssh_port] = nil
144
+ @knife.config[:identity_file] = "~/.ssh/me.rsa"
145
+ @knife.stub!(:read_template).and_return("")
146
+ @knife_ssh = @knife.knife_ssh
147
+ end
148
+
149
+ it "configures the hostname" do
150
+ @knife_ssh.name_args.first.should == "foo.example.com"
151
+ end
152
+
153
+ it "configures the ssh user" do
154
+ @knife_ssh.config[:ssh_user].should == 'rooty'
155
+ end
156
+
157
+ it "configures the ssh password" do
158
+ @knife_ssh.config[:ssh_password].should == 'open_sesame'
159
+ end
160
+
161
+ it "configures the ssh port" do
162
+ @knife_ssh.config[:ssh_port].should == '4001'
163
+ end
164
+
165
+ it "configures the ssh identity file" do
166
+ @knife_ssh.config[:identity_file].should == '~/.ssh/me.rsa'
167
+ end
148
168
  end
149
169
 
150
- it "configures the ssh user" do
151
- @knife_ssh.config[:ssh_user].should == 'rooty'
152
- end
153
-
154
- it "configures the ssh password" do
155
- @knife_ssh.config[:ssh_password].should == 'open_sesame'
156
- end
157
-
158
- it "configures the ssh port" do
159
- @knife_ssh.config[:ssh_port].should == '4001'
160
- end
161
-
162
- it "configures the ssh identity file" do
163
- @knife_ssh.config[:identity_file].should == '~/.ssh/me.rsa'
164
- end
170
+ context "from the knife config file" do
171
+ before do
172
+ @knife.name_args = ["config.example.com"]
173
+ @knife.config[:ssh_user] = nil
174
+ @knife.config[:ssh_port] = nil
175
+ @knife.config[:ssh_gateway] = nil
176
+ @knife.config[:identity_file] = nil
177
+ @knife.config[:host_key_verify] = nil
178
+ Chef::Config[:knife][:ssh_user] = "curiosity"
179
+ Chef::Config[:knife][:ssh_port] = "2430"
180
+ Chef::Config[:knife][:identity_file] = "~/.ssh/you.rsa"
181
+ Chef::Config[:knife][:ssh_gateway] = "towel.blinkenlights.nl"
182
+ Chef::Config[:knife][:host_key_verify] = true
183
+ @knife.stub!(:read_template).and_return("")
184
+ @knife_ssh = @knife.knife_ssh
185
+ end
186
+
187
+ it "configures the ssh user" do
188
+ @knife_ssh.config[:ssh_user].should == 'curiosity'
189
+ end
190
+
191
+ it "configures the ssh port" do
192
+ @knife_ssh.config[:ssh_port].should == '2430'
193
+ end
194
+
195
+ it "configures the ssh identity file" do
196
+ @knife_ssh.config[:identity_file].should == '~/.ssh/you.rsa'
197
+ end
198
+
199
+ it "configures the ssh gateway" do
200
+ @knife_ssh.config[:ssh_gateway].should == 'towel.blinkenlights.nl'
201
+ end
202
+
203
+ it "configures the host key verify mode" do
204
+ @knife_ssh.config[:host_key_verify].should == true
205
+ end
165
206
  end
166
207
 
167
208
  describe "when falling back to password auth when host key auth fails" do
@@ -22,40 +22,41 @@ describe Chef::Knife::ClientReregister do
22
22
  before(:each) do
23
23
  @knife = Chef::Knife::ClientReregister.new
24
24
  @knife.name_args = [ 'adam' ]
25
- @client_mock = mock('client_mock')
26
- @client_mock.stub!(:save).and_return({ 'private_key' => 'foo_key' })
27
- Chef::ApiClient.stub!(:load).and_return(@client_mock)
25
+ @client_mock = mock('client_mock', :private_key => "foo_key")
28
26
  @stdout = StringIO.new
29
27
  @knife.ui.stub!(:stdout).and_return(@stdout)
30
28
  end
31
29
 
32
- describe 'run' do
33
- it 'should load and save the client' do
34
- Chef::ApiClient.should_receive(:load).with('adam').and_return(@client_mock)
35
- @client_mock.should_receive(:save).with(true).and_return({'private_key' => 'foo_key'})
36
- @knife.run
37
- end
38
-
39
- it 'should output the private key' do
40
- @knife.run
41
- @stdout.string.should match /foo_key/
30
+ context "when no client name is given on the command line" do
31
+ before do
32
+ @knife.name_args = []
42
33
  end
43
34
 
44
35
  it 'should print usage and exit when a client name is not provided' do
45
- @knife.name_args = []
46
36
  @knife.should_receive(:show_usage)
47
37
  @knife.ui.should_receive(:fatal)
48
38
  lambda { @knife.run }.should raise_error(SystemExit)
49
39
  end
40
+ end
41
+
42
+ context 'when not configured for file output' do
43
+ it 'reregisters the client and prints the key' do
44
+ Chef::ApiClient.should_receive(:reregister).with('adam').and_return(@client_mock)
45
+ @knife.run
46
+ @stdout.string.should match( /foo_key/ )
47
+ end
48
+ end
50
49
 
51
- describe 'with -f or --file' do
52
- it 'should write the private key to a file' do
53
- @knife.config[:file] = '/tmp/monkeypants'
54
- filehandle = mock('Filehandle')
55
- filehandle.should_receive(:print).with('foo_key')
56
- File.should_receive(:open).with('/tmp/monkeypants', 'w').and_yield(filehandle)
57
- @knife.run
58
- end
50
+ context 'when configured for file output' do
51
+ it 'should write the private key to a file' do
52
+ Chef::ApiClient.should_receive(:reregister).with('adam').and_return(@client_mock)
53
+
54
+ @knife.config[:file] = '/tmp/monkeypants'
55
+ filehandle = StringIO.new
56
+ File.should_receive(:open).with('/tmp/monkeypants', 'w').and_yield(filehandle)
57
+ @knife.run
58
+ filehandle.string.should == "foo_key"
59
59
  end
60
60
  end
61
+
61
62
  end