chef 10.14.2 → 10.14.4.rc.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. data/distro/common/html/chef-client.8.html +3 -3
  2. data/distro/common/html/chef-expander.8.html +3 -3
  3. data/distro/common/html/chef-expanderctl.8.html +3 -3
  4. data/distro/common/html/chef-server-webui.8.html +3 -3
  5. data/distro/common/html/chef-server.8.html +3 -3
  6. data/distro/common/html/chef-solo.8.html +3 -3
  7. data/distro/common/html/chef-solr.8.html +3 -3
  8. data/distro/common/html/knife-bootstrap.1.html +3 -3
  9. data/distro/common/html/knife-client.1.html +4 -4
  10. data/distro/common/html/knife-configure.1.html +3 -3
  11. data/distro/common/html/knife-cookbook-site.1.html +3 -3
  12. data/distro/common/html/knife-cookbook.1.html +3 -3
  13. data/distro/common/html/knife-data-bag.1.html +3 -3
  14. data/distro/common/html/knife-environment.1.html +6 -6
  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 +6 -6
  19. data/distro/common/html/knife-search.1.html +3 -3
  20. data/distro/common/html/knife-ssh.1.html +3 -3
  21. data/distro/common/html/knife-status.1.html +3 -3
  22. data/distro/common/html/knife-tag.1.html +4 -4
  23. data/distro/common/html/knife.1.html +3 -3
  24. data/distro/common/html/shef.1.html +7 -7
  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/config.rb +1 -0
  50. data/lib/chef/formatters/error_inspectors/compile_error_inspector.rb +12 -3
  51. data/lib/chef/formatters/error_inspectors/cookbook_resolve_error_inspector.rb +0 -1
  52. data/lib/chef/formatters/error_inspectors/registration_error_inspector.rb +1 -1
  53. data/lib/chef/formatters/error_inspectors/resource_failure_inspector.rb +5 -5
  54. data/lib/chef/knife/data_bag_edit.rb +1 -1
  55. data/lib/chef/knife/ssh.rb +15 -4
  56. data/lib/chef/platform.rb +1 -1
  57. data/lib/chef/provider/deploy.rb +9 -5
  58. data/lib/chef/provider/http_request.rb +15 -12
  59. data/lib/chef/version.rb +1 -1
  60. data/spec/data/cookbooks/angrybash/recipes/default.rb +8 -0
  61. data/spec/support/shared/unit/api_error_inspector.rb +14 -2
  62. data/spec/unit/config_spec.rb +17 -5
  63. data/spec/unit/cookbook_loader_spec.rb +5 -4
  64. data/spec/unit/formatters/error_inspectors/compile_error_inspector_spec.rb +58 -0
  65. data/spec/unit/formatters/error_inspectors/cookbook_resolve_error_inspector_spec.rb +18 -0
  66. data/spec/unit/formatters/error_inspectors/resource_failure_inspector_spec.rb +30 -0
  67. data/spec/unit/knife/ssh_spec.rb +63 -24
  68. data/spec/unit/platform_spec.rb +15 -3
  69. data/spec/unit/provider/deploy_spec.rb +45 -10
  70. data/spec/unit/provider/http_request_spec.rb +6 -0
  71. metadata +14 -9
@@ -55,13 +55,11 @@ class Chef
55
55
  relevant_lines = ["# In #{file}\n\n"]
56
56
 
57
57
 
58
- current_line = line - 2
58
+ current_line = line - 1
59
+ current_line = 0 if current_line < 0
59
60
  nesting = 0
60
61
 
61
- relevant_lines << format_line(current_line, lines[current_line])
62
-
63
62
  loop do
64
- current_line += 1
65
63
 
66
64
  # low rent parser. try to gracefully handle nested blocks in resources
67
65
  nesting += 1 if lines[current_line] =~ /[\s]+do[\s]*/
@@ -69,9 +67,11 @@ class Chef
69
67
 
70
68
  relevant_lines << format_line(current_line, lines[current_line])
71
69
 
72
- break if lines[current_line].nil?
70
+ break if lines[current_line + 1].nil?
73
71
  break if current_line >= (line + 50)
74
72
  break if nesting <= 0
73
+
74
+ current_line += 1
75
75
  end
76
76
  relevant_lines << format_line(current_line + 1, lines[current_line + 1]) if lines[current_line + 1]
77
77
  relevant_lines.join("")
@@ -84,7 +84,7 @@ class Chef
84
84
  output = edit_item(item)
85
85
  rest.put_rest("data/#{@name_args[0]}/#{@name_args[1]}", output)
86
86
  stdout.puts("Saved data_bag_item[#{@name_args[1]}]")
87
- output(format_for_display(object.raw_data)) if config[:print_after]
87
+ ui.output(output) if config[:print_after]
88
88
  end
89
89
  end
90
90
  end
@@ -48,8 +48,8 @@ class Chef
48
48
  option :attribute,
49
49
  :short => "-a ATTR",
50
50
  :long => "--attribute ATTR",
51
- :description => "The attribute to use for opening the connection - default is fqdn",
52
- :proc => Proc.new { |key| Chef::Config[:knife][:ssh_attribute] = key }
51
+ :description => "The attribute to use for opening the connection - default depends on the context",
52
+ :proc => Proc.new { |key| Chef::Config[:knife][:ssh_attribute] = key.strip }
53
53
 
54
54
  option :manual,
55
55
  :short => "-m",
@@ -128,6 +128,8 @@ class Chef
128
128
  # see #configure_attribute for the source of config[:attribute] and config[:override_attribute]
129
129
  if !config[:override_attribute] && item[:cloud] and item[:cloud][:public_hostname]
130
130
  i = item[:cloud][:public_hostname]
131
+ elsif config[:override_attribute]
132
+ i = format_for_display(item)[config[:override_attribute]]
131
133
  else
132
134
  i = format_for_display(item)[config[:attribute]]
133
135
  end
@@ -135,7 +137,16 @@ class Chef
135
137
  end
136
138
  r
137
139
  end
138
- (ui.fatal("No nodes returned from search!"); exit 10) if list.length == 0
140
+ if list.length == 0
141
+ if @action_nodes.length == 0
142
+ ui.fatal("No nodes returned from search!")
143
+ else
144
+ ui.fatal("#{@action_nodes.length} #{@action_nodes.length > 1 ? "nodes":"node"} found, " +
145
+ "but do not have the required attribute to stablish the connection. " +
146
+ "Try setting another attribute to open the connection using --attribute.")
147
+ end
148
+ exit 10
149
+ end
139
150
  session_from_list(list)
140
151
  end
141
152
 
@@ -346,7 +357,7 @@ class Chef
346
357
  # Thus we can differentiate between a config file value and a command line override at this point by checking config[:attribute]
347
358
  # We can tell here if fqdn was passed from the command line, rather than being the default, by checking config[:attribute]
348
359
  # However, after here, we cannot tell these things, so we must preserve config[:attribute]
349
- config[:override_attribute] = config[:attribute]
360
+ config[:override_attribute] = config[:attribute] || Chef::Config[:knife][:ssh_attribute]
350
361
  config[:attribute] = (Chef::Config[:knife][:ssh_attribute] ||
351
362
  config[:attribute] ||
352
363
  "fqdn").strip
data/lib/chef/platform.rb CHANGED
@@ -369,7 +369,7 @@ class Chef
369
369
  return platform, version
370
370
  end
371
371
 
372
- def provider_for_resource(resource, action)
372
+ def provider_for_resource(resource, action=:nothing)
373
373
  node = resource.run_context && resource.run_context.node
374
374
  raise ArgumentError, "Cannot find the provider for a resource with no run context set" unless node
375
375
  provider = find_provider_for_node(node, resource).new(resource, resource.run_context)
@@ -149,6 +149,12 @@ class Chef
149
149
 
150
150
  def deploy
151
151
  verify_directories_exist
152
+ # CHEF-3435: We need to create the directories if they don't exist before calling the
153
+ # scm_provider because it expects them to be there in its own assertations
154
+ unless self.converge_actions.empty?
155
+ Chef::Log.info "#{@new_resource} running collected converge_actions before calling scm_provider"
156
+ self.converge_actions.converge!
157
+ end
152
158
  update_cached_repo # no converge-by - scm provider will dothis
153
159
  enforce_ownership
154
160
  copy_cached_repo
@@ -402,11 +408,9 @@ class Chef
402
408
  end
403
409
 
404
410
  def run_callback_from_file(callback_file)
405
- if ::File.exist?(callback_file)
406
- Dir.chdir(release_path) do
407
- Chef::Log.info "#{@new_resource} running deploy hook #{callback_file}"
408
- recipe_eval { from_file(callback_file) }
409
- end
411
+ Dir.chdir(release_path) do
412
+ Chef::Log.info "#{@new_resource} queueing checkdeploy hook #{callback_file}"
413
+ recipe_eval { from_file(callback_file) if ::File.exist?(callback_file) }
410
414
  end
411
415
  end
412
416
 
@@ -34,18 +34,21 @@ class Chef
34
34
 
35
35
  # Send a HEAD request to @new_resource.url, with ?message=@new_resource.message
36
36
  def action_head
37
- converge_by("#{@new_resource} HEAD to #{@new_resource.url}") do
38
- message = check_message(@new_resource.message)
39
- modified = @rest.run_request(
40
- :HEAD,
41
- @rest.create_url("#{@new_resource.url}?message=#{message}"),
42
- @new_resource.headers,
43
- false,
44
- 10,
45
- false
46
- )
47
- Chef::Log.info("#{@new_resource} HEAD to #{@new_resource.url} successful")
48
- Chef::Log.debug("#{@new_resource} HEAD request response: #{modified}")
37
+ message = check_message(@new_resource.message)
38
+ # returns true from Chef::REST if returns 2XX (Net::HTTPSuccess)
39
+ modified = @rest.run_request(
40
+ :HEAD,
41
+ @rest.create_url("#{@new_resource.url}?message=#{message}"),
42
+ @new_resource.headers,
43
+ false,
44
+ 10,
45
+ false
46
+ )
47
+ Chef::Log.info("#{@new_resource} HEAD to #{@new_resource.url} successful")
48
+ Chef::Log.debug("#{@new_resource} HEAD request response: #{modified}")
49
+ # :head is usually used to trigger notifications, which converge_by now does
50
+ if modified
51
+ converge_by("#{@new_resource} HEAD to #{@new_resource.url} returned modified, trigger notifications") {}
49
52
  end
50
53
  end
51
54
 
data/lib/chef/version.rb CHANGED
@@ -17,7 +17,7 @@
17
17
 
18
18
  class Chef
19
19
  CHEF_ROOT = File.dirname(File.expand_path(File.dirname(__FILE__)))
20
- VERSION = '10.14.2'
20
+ VERSION = '10.14.4.rc.0'
21
21
  end
22
22
 
23
23
  # NOTE: the Chef::Version class is defined in version_class.rb
@@ -0,0 +1,8 @@
1
+ bash "go off the rails" do
2
+ code <<-END
3
+ for i in localhost 127.0.0.1 #{Socket.gethostname()}
4
+ do
5
+ echo "grant all on *.* to root@'$i' identified by 'a_password'; flush privileges;" | mysql -u root -h 127.0.0.1
6
+ done
7
+ END
8
+ end
@@ -6,9 +6,9 @@
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
7
7
  # you may not use this file except in compliance with the License.
8
8
  # You may obtain a copy of the License at
9
- #
9
+ #
10
10
  # http://www.apache.org/licenses/LICENSE-2.0
11
- #
11
+ #
12
12
  # Unless required by applicable law or agreed to in writing, software
13
13
  # distributed under the License is distributed on an "AS IS" BASIS,
14
14
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -177,4 +177,16 @@ shared_examples_for "an api error inspector" do
177
177
  end
178
178
  end
179
179
 
180
+ describe "when explaining an unknown error" do
181
+ before do
182
+ @exception = RuntimeError.new("(exception) something went wrong")
183
+ @inspector = described_class.new(@node_name, @exception, @config)
184
+ @inspector.add_explanation(@description)
185
+ end
186
+
187
+ it "prints a nice message" do
188
+ @description.display(@outputter)
189
+ end
190
+ end
191
+
180
192
  end
@@ -24,11 +24,7 @@ describe Chef::Config do
24
24
  @original_env = { 'HOME' => ENV['HOME'], 'SYSTEMDRIVE' => ENV['SYSTEMDRIVE'], 'HOMEPATH' => ENV['HOMEPATH'], 'USERPROFILE' => ENV['USERPROFILE'] }
25
25
  end
26
26
 
27
- describe "config attribute writer: chef_server_url" do
28
- before do
29
- Chef::Config.chef_server_url = "https://junglist.gen.nz"
30
- end
31
-
27
+ shared_examples_for "server URL" do
32
28
  it "should set the registration url" do
33
29
  Chef::Config.registration_url.should == "https://junglist.gen.nz"
34
30
  end
@@ -50,6 +46,22 @@ describe Chef::Config do
50
46
  end
51
47
  end
52
48
 
49
+ describe "config attribute writer: chef_server_url" do
50
+ before do
51
+ Chef::Config.chef_server_url = "https://junglist.gen.nz"
52
+ end
53
+
54
+ it_behaves_like "server URL"
55
+ end
56
+
57
+ context "when the url has a leading space" do
58
+ before do
59
+ Chef::Config.chef_server_url = " https://junglist.gen.nz"
60
+ end
61
+
62
+ it_behaves_like "server URL"
63
+ end
64
+
53
65
  describe "class method: manage_secret_key" do
54
66
  before do
55
67
  Chef::FileCache.stub!(:load).and_return(true)
@@ -59,10 +59,11 @@ describe Chef::CookbookLoader do
59
59
  @cookbook_loader.each do |cookbook_name, cookbook|
60
60
  seen << cookbook_name
61
61
  end
62
- seen[0].should == "apache2"
63
- seen[1].should == "borken"
64
- seen[2].should == "java"
65
- seen[3].should == "openldap"
62
+ seen[0].should == "angrybash"
63
+ seen[1].should == "apache2"
64
+ seen[2].should == "borken"
65
+ seen[3].should == "java"
66
+ seen[4].should == "openldap"
66
67
  end
67
68
  end
68
69
 
@@ -85,6 +85,10 @@ describe Chef::Formatters::ErrorInspectors::CompileErrorInspector do
85
85
  @inspector.add_explanation(@description)
86
86
  end
87
87
 
88
+ it "finds the line number of the error from the stacktrace" do
89
+ @inspector.culprit_line.should == 14
90
+ end
91
+
88
92
  it "prints a pretty message" do
89
93
  @description.display(@outputter)
90
94
  end
@@ -124,10 +128,64 @@ describe Chef::Formatters::ErrorInspectors::CompileErrorInspector do
124
128
  @inspector.add_explanation(@description)
125
129
  end
126
130
 
131
+ it "finds the culprit recipe name from the stacktrace" do
132
+ @inspector.culprit_file.should == "C:/opscode/chef/var/cache/cookbooks/foo/recipes/default.rb"
133
+ end
134
+
135
+ it "finds the line number of the error from the stack trace" do
136
+ @inspector.culprit_line.should == 14
137
+ end
138
+
127
139
  it "prints a pretty message" do
128
140
  @description.display(@outputter)
129
141
  end
130
142
  end
131
143
 
144
+ describe "when explaining an error on windows, and the backtrace lowercases the drive letter" do
145
+ before do
146
+ Chef::Config.stub!(:cookbook_path).and_return([ "C:/opscode/chef/var/cache/cookbooks" ])
147
+ recipe_lines = BAD_RECIPE.split("\n").map {|l| l << "\n" }
148
+ IO.should_receive(:readlines).with("c:/opscode/chef/var/cache/cookbooks/foo/recipes/default.rb").and_return(recipe_lines)
149
+ @trace = [
150
+ "c:/opscode/chef/var/cache/cookbooks/foo/recipes/default.rb:14 in `from_file'",
151
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:144:in `rescue in block in load_libraries'",
152
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:138:in `block in load_libraries'",
153
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:230:in `call'",
154
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:230:in `block (2 levels) in foreach_cookbook_load_segment'",
155
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:229:in `each'",
156
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:229:in `block in foreach_cookbook_load_segment'",
157
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:227:in `each'",
158
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:227:in `foreach_cookbook_load_segment'",
159
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:137:in `load_libraries'",
160
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:62:in `load'",
161
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/client.rb:198:in `setup_run_context'",
162
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/client.rb:418:in `do_run'",
163
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/client.rb:176:in `run'",
164
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/application/client.rb:283:in `block in run_application'",
165
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/application/client.rb:270:in `loop'",
166
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/application/client.rb:270:in `run_application'",
167
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/application.rb:70:in `run'",
168
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/bin/chef-client:26:in `<top (required)>'",
169
+ "c:/opscode/chef/bin/chef-client:19:in `load'",
170
+ "c:/opscode/chef/bin/chef-client:19:in `<main>'"
171
+ ]
172
+ @exception.set_backtrace(@trace)
173
+ @path = "/var/chef/cache/cookbooks/syntax-err/recipes/default.rb"
174
+ @inspector = described_class.new(@path, @exception)
175
+ @inspector.add_explanation(@description)
176
+ end
177
+
178
+ it "finds the culprit recipe name from the stacktrace" do
179
+ @inspector.culprit_file.should == "c:/opscode/chef/var/cache/cookbooks/foo/recipes/default.rb"
180
+ end
181
+
182
+ it "finds the line number of the error from the stack trace" do
183
+ @inspector.culprit_line.should == 14
184
+ end
185
+
186
+ it "prints a pretty message" do
187
+ @description.display(@outputter)
188
+ end
189
+ end
132
190
 
133
191
  end
@@ -28,6 +28,24 @@ describe Chef::Formatters::ErrorInspectors::CookbookResolveErrorInspector do
28
28
  #@outputter = Chef::Formatters::Outputter.new(STDOUT, STDERR)
29
29
  end
30
30
 
31
+ describe "when explaining a 403 error" do
32
+ before do
33
+
34
+ @response_body = %Q({"error": [{"message": "gtfo"}])
35
+ @response = Net::HTTPForbidden.new("1.1", "403", "(response) forbidden")
36
+ @response.stub!(:body).and_return(@response_body)
37
+ @exception = Net::HTTPServerException.new("(exception) forbidden", @response)
38
+
39
+ @inspector = Chef::Formatters::ErrorInspectors::CookbookResolveErrorInspector.new(@expanded_run_list, @exception)
40
+ @inspector.add_explanation(@description)
41
+ end
42
+
43
+ it "prints a nice message" do
44
+ lambda { @description.display(@outputter) }.should_not raise_error
45
+ end
46
+
47
+ end
48
+
31
49
  describe "when explaining a PreconditionFailed (412) error with current error message style" do
32
50
  # Chef currently returns error messages with some fields as JSON strings,
33
51
  # which must be re-parsed to get the actual data.
@@ -98,5 +98,35 @@ describe Chef::Formatters::ErrorInspectors::ResourceFailureInspector do
98
98
  @inspector.recipe_snippet.should match(/^# In \/home\/btm/)
99
99
  end
100
100
  end
101
+
102
+ describe "when examining a resource that confuses the parser" do
103
+ before do
104
+ angry_bash_recipe = File.expand_path("cookbooks/angrybash/recipes/default.rb", CHEF_SPEC_DATA)
105
+ source_line = "#{angry_bash_recipe}:1:in `<main>'"
106
+
107
+ # source_line = caller(0)[0]; @resource = bash "go off the rails" do
108
+ # code <<-END
109
+ # for i in localhost 127.0.0.1 #{Socket.gethostname()}
110
+ # do
111
+ # echo "grant all on *.* to root@'$i' identified by 'a_password'; flush privileges;" | mysql -u root -h 127.0.0.1
112
+ # done
113
+ # END
114
+ # end
115
+ @resource = eval(IO.read(angry_bash_recipe))
116
+ @resource.source_line = source_line
117
+ @inspector = Chef::Formatters::ErrorInspectors::ResourceFailureInspector.new(@resource, :create, @exception)
118
+
119
+ @exception.set_backtrace(@trace)
120
+ @inspector = Chef::Formatters::ErrorInspectors::ResourceFailureInspector.new(@resource, :create, @exception)
121
+ end
122
+
123
+ it "does not generate an error" do
124
+ lambda { @inspector.add_explanation(@description) }.should_not raise_error(TypeError)
125
+ @description.display(@outputter)
126
+ end
127
+ end
128
+
101
129
  end
130
+
131
+
102
132
  end
@@ -23,11 +23,13 @@ require 'net/ssh/multi'
23
23
  describe Chef::Knife::Ssh do
24
24
  before(:all) do
25
25
  @original_config = Chef::Config.hash_dup
26
+ @original_knife_config = Chef::Config[:knife].dup
26
27
  Chef::Config[:client_key] = CHEF_SPEC_DATA + "/ssl/private_key.pem"
27
28
  end
28
29
 
29
30
  after(:all) do
30
31
  Chef::Config.configuration = @original_config
32
+ Chef::Config[:knife] = @original_knife_config
31
33
  end
32
34
 
33
35
  before do
@@ -36,8 +38,10 @@ describe Chef::Knife::Ssh do
36
38
  @knife.config[:attribute] = "fqdn"
37
39
  @node_foo = Chef::Node.new('foo')
38
40
  @node_foo[:fqdn] = "foo.example.org"
39
- @node_bar = Chef::Node.new('foo')
41
+ @node_foo[:ipaddress] = "10.0.0.1"
42
+ @node_bar = Chef::Node.new('bar')
40
43
  @node_bar[:fqdn] = "bar.example.org"
44
+ @node_bar[:ipaddress] = "10.0.0.2"
41
45
  end
42
46
 
43
47
  describe "#configure_session" do
@@ -47,27 +51,36 @@ describe Chef::Knife::Ssh do
47
51
  @query = Chef::Search::Query.new
48
52
  end
49
53
 
50
- def self.should_return_array_of_attributes
51
- it "returns an array of the specified attributes if configured" do
54
+ def configure_query(node_array)
55
+ @query.stub!(:search).and_return([node_array])
56
+ Chef::Search::Query.stub!(:new).and_return(@query)
57
+ end
58
+
59
+ def self.should_return_specified_attributes
60
+ it "returns an array of the attributes specified on the command line OR config file, if only one is set" do
52
61
  @knife.config[:attribute] = "ipaddress"
53
62
  @knife.config[:override_attribute] = "ipaddress"
54
- @node_foo[:ipaddress] = "10.0.0.1"
55
- @node_bar[:ipaddress] = "10.0.0.2"
56
- @query.stub!(:search).and_return([[@node_foo, @node_bar]])
57
- Chef::Search::Query.stub!(:new).and_return(@query)
63
+ configure_query([@node_foo, @node_bar])
64
+ @knife.should_receive(:session_from_list).with(['10.0.0.1', '10.0.0.2'])
65
+ @knife.configure_session
66
+ end
67
+
68
+ it "returns an array of the attributes specified on the command line even when a config value is set" do
69
+ @knife.config[:attribute] = "config_file" # this value will be the config file
70
+ @knife.config[:override_attribute] = "ipaddress" # this is the value of the command line via #configure_attribute
71
+ configure_query([@node_foo, @node_bar])
58
72
  @knife.should_receive(:session_from_list).with(['10.0.0.1', '10.0.0.2'])
59
73
  @knife.configure_session
60
74
  end
61
75
  end
62
76
 
63
77
  it "searchs for and returns an array of fqdns" do
64
- @query.stub!(:search).and_return([[@node_foo, @node_bar]])
65
- Chef::Search::Query.stub!(:new).and_return(@query)
78
+ configure_query([@node_foo, @node_bar])
66
79
  @knife.should_receive(:session_from_list).with(['foo.example.org', 'bar.example.org'])
67
80
  @knife.configure_session
68
81
  end
69
82
 
70
- should_return_array_of_attributes
83
+ should_return_specified_attributes
71
84
 
72
85
  context "when cloud hostnames are available" do
73
86
  before do
@@ -78,22 +91,35 @@ describe Chef::Knife::Ssh do
78
91
  end
79
92
 
80
93
  it "returns an array of cloud public hostnames" do
81
- @query.stub!(:search).and_return([[@node_foo, @node_bar]])
82
- Chef::Search::Query.stub!(:new).and_return(@query)
94
+ configure_query([@node_foo, @node_bar])
83
95
  @knife.should_receive(:session_from_list).with(['ec2-10-0-0-1.compute-1.amazonaws.com', 'ec2-10-0-0-2.compute-1.amazonaws.com'])
84
96
  @knife.configure_session
85
97
  end
86
-
87
- should_return_array_of_attributes
98
+
99
+ should_return_specified_attributes
88
100
  end
89
101
 
90
102
  it "should raise an error if no host are found" do
91
- @query.stub!(:search).and_return([[ ]])
92
- Chef::Search::Query.stub!(:new).and_return(@query)
103
+ configure_query([ ])
93
104
  @knife.ui.should_receive(:fatal)
94
105
  @knife.should_receive(:exit).with(10)
95
106
  @knife.configure_session
96
107
  end
108
+
109
+ context "when there are some hosts found but they do not have an attribute to connect with" do
110
+ before do
111
+ @query.stub!(:search).and_return([[@node_foo, @node_bar]])
112
+ @node_foo[:fqdn] = nil
113
+ @node_bar[:fqdn] = nil
114
+ Chef::Search::Query.stub!(:new).and_return(@query)
115
+ end
116
+
117
+ it "should raise a specific error (CHEF-3402)" do
118
+ @knife.ui.should_receive(:fatal).with(/^2 nodes found/)
119
+ @knife.should_receive(:exit).with(10)
120
+ @knife.configure_session
121
+ end
122
+ end
97
123
  end
98
124
 
99
125
  context "manual is set to true" do
@@ -121,24 +147,37 @@ describe Chef::Knife::Ssh do
121
147
  end
122
148
 
123
149
  it "should return the value set in the configuration file" do
124
- Chef::Config[:knife][:ssh_attribute] = "magic"
150
+ Chef::Config[:knife][:ssh_attribute] = "config_file"
125
151
  @knife.configure_attribute
126
- @knife.config[:attribute].should == "magic"
152
+ @knife.config[:attribute].should == "config_file"
127
153
  end
128
154
 
129
155
  it "should return the value set on the command line" do
130
- @knife.config[:attribute] = "penguins"
156
+ @knife.config[:attribute] = "command_line"
131
157
  @knife.configure_attribute
132
- @knife.config[:attribute].should == "penguins"
158
+ @knife.config[:attribute].should == "command_line"
133
159
  end
134
160
 
135
- it "should set override_attribute to the value of attribute" do
136
- @knife.config[:attribute] = "penguins"
161
+ it "should set override_attribute to the value of attribute from the command line" do
162
+ @knife.config[:attribute] = "command_line"
137
163
  @knife.configure_attribute
138
- @knife.config[:attribute].should == "penguins"
139
- @knife.config[:override_attribute].should == "penguins"
164
+ @knife.config[:attribute].should == "command_line"
165
+ @knife.config[:override_attribute].should == "command_line"
140
166
  end
141
167
 
168
+ it "should set override_attribute to the value of attribute from the config file" do
169
+ Chef::Config[:knife][:ssh_attribute] = "config_file"
170
+ @knife.configure_attribute
171
+ @knife.config[:attribute].should == "config_file"
172
+ @knife.config[:override_attribute].should == "config_file"
173
+ end
174
+
175
+ it "should prefer the command line over the config file for the value of override_attribute" do
176
+ Chef::Config[:knife][:ssh_attribute] = "config_file"
177
+ @knife.config[:attribute] = "command_line"
178
+ @knife.configure_attribute
179
+ @knife.config[:override_attribute].should == "command_line"
180
+ end
142
181
  end
143
182
 
144
183
  end