chef 10.14.2 → 10.14.4.rc.0

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 (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