chef 11.10.4 → 11.12.0.alpha.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/CONTRIBUTING.md +6 -6
  3. data/README.md +1 -1
  4. data/lib/chef/api_client.rb +1 -3
  5. data/lib/chef/application.rb +2 -1
  6. data/lib/chef/application/client.rb +11 -1
  7. data/lib/chef/client.rb +24 -9
  8. data/lib/chef/cookbook/syntax_check.rb +107 -6
  9. data/lib/chef/dsl/reboot_pending.rb +61 -0
  10. data/lib/chef/exceptions.rb +12 -1
  11. data/lib/chef/formatters/error_descriptor.rb +1 -1
  12. data/lib/chef/http/remote_request_id.rb +46 -0
  13. data/lib/chef/knife/bootstrap.rb +1 -1
  14. data/lib/chef/knife/bootstrap/README.md +12 -0
  15. data/lib/chef/knife/bootstrap/chef-full.erb +3 -0
  16. data/lib/chef/knife/client_create.rb +6 -0
  17. data/lib/chef/knife/client_delete.rb +15 -1
  18. data/lib/chef/knife/raw.rb +1 -0
  19. data/lib/chef/node.rb +1 -1
  20. data/lib/chef/node/attribute_collections.rb +8 -1
  21. data/lib/chef/node/immutable_collections.rb +8 -1
  22. data/lib/chef/provider/deploy.rb +1 -1
  23. data/lib/chef/provider/group.rb +1 -1
  24. data/lib/chef/provider/ifconfig/debian.rb +19 -8
  25. data/lib/chef/provider/ohai.rb +6 -5
  26. data/lib/chef/provider/service/macosx.rb +68 -14
  27. data/lib/chef/recipe.rb +2 -0
  28. data/lib/chef/request_id.rb +37 -0
  29. data/lib/chef/resource.rb +2 -0
  30. data/lib/chef/resource_reporter.rb +7 -4
  31. data/lib/chef/rest.rb +5 -1
  32. data/lib/chef/run_status.rb +4 -1
  33. data/lib/chef/server_api.rb +3 -1
  34. data/lib/chef/version.rb +2 -2
  35. data/spec/functional/dsl/reboot_pending_spec.rb +118 -0
  36. data/spec/functional/resource/base.rb +1 -3
  37. data/spec/functional/resource/deploy_revision_spec.rb +192 -1
  38. data/spec/functional/resource/git_spec.rb +1 -1
  39. data/spec/functional/resource/ohai_spec.rb +65 -0
  40. data/spec/functional/resource/registry_spec.rb +4 -5
  41. data/spec/integration/client/client_spec.rb +14 -0
  42. data/spec/spec_helper.rb +1 -2
  43. data/spec/support/shared/functional/windows_script.rb +1 -2
  44. data/spec/unit/api_client_spec.rb +46 -0
  45. data/spec/unit/client_spec.rb +345 -229
  46. data/spec/unit/cookbook/syntax_check_spec.rb +0 -1
  47. data/spec/unit/dsl/reboot_pending_spec.rb +100 -0
  48. data/spec/unit/knife/client_create_spec.rb +29 -1
  49. data/spec/unit/knife/client_delete_spec.rb +44 -1
  50. data/spec/unit/knife_spec.rb +55 -0
  51. data/spec/unit/node/attribute_spec.rb +7 -0
  52. data/spec/unit/node/immutable_collections_spec.rb +5 -1
  53. data/spec/unit/provider/group_spec.rb +5 -0
  54. data/spec/unit/provider/ifconfig/debian_spec.rb +251 -24
  55. data/spec/unit/provider/ohai_spec.rb +2 -3
  56. data/spec/unit/provider/service/macosx_spec.rb +29 -11
  57. data/spec/unit/resource_reporter_spec.rb +1 -1
  58. data/spec/unit/rest_spec.rb +38 -13
  59. metadata +151 -194
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9898c6f7591ed887a6598b3d69e579eb80e91219
4
+ data.tar.gz: a149ede107dbfe06de90825b9fc14f17eda23117
5
+ SHA512:
6
+ metadata.gz: 91da0bbf0cf8981e3300510bb4b8c7e8479f9624c37e4d3d0abb3398fe5dff5692f2cfdb8a7b47362d139e215b52111f29346a5504a187c0a8f39ecb67fd20cd
7
+ data.tar.gz: fe75d1790cd62872a44c86c9801919f3e3479c47e5389e03d5f95fbbe3292a4e4461759744b2cc2b54cf07cfbb90eb45f702e92c3dd529caec97abe94f66eb10
@@ -24,7 +24,7 @@ Chef uses the Apache 2.0 license to strike a balance between open contribution a
24
24
  The license tells you what rights you have that are provided by the copyright holder. It is important that the contributor fully understands what rights
25
25
  they are licensing and agrees to them. Sometimes the copyright holder isn't the contributor, most often when the contributor is doing work for a company.
26
26
 
27
- To make a good faith effort to ensure these criteria are met, Opscode requires a Contributor License Agreement (CLA) or a Corporate Contributor License
27
+ To make a good faith effort to ensure these criteria are met, Chef requires a Contributor License Agreement (CLA) or a Corporate Contributor License
28
28
  Agreement (CCLA) for all contributions. This is without exception due to some matters not being related to copyright and to avoid having to continually
29
29
  check with our lawyers about small patches.
30
30
 
@@ -74,7 +74,7 @@ helpful to be clear about your use case and change so they can understand it eve
74
74
 
75
75
  ### Github and Pull Requests
76
76
 
77
- All of Opscode's open source projects are available on [Github](http://www.github.com/opscode).
77
+ All of Chef's open source projects are available on [Github](http://www.github.com/opscode).
78
78
 
79
79
  We don't require you to use Github, and we will even take patch diffs attached to tickets on the tracker.
80
80
  However Github has a lot of convenient features, such as being able to see a diff of changes between a
@@ -115,7 +115,7 @@ and accounting for it.
115
115
 
116
116
  ## Code Review
117
117
 
118
- Opscode regularly reviews code contributions and provides suggestions for improvement in the code itself or the implementation.
118
+ Chef regularly reviews code contributions and provides suggestions for improvement in the code itself or the implementation.
119
119
 
120
120
  We find contributions by searching the ticket tracker for _resolved_ tickets with a status of _fixed_. If we have feedback we will
121
121
  reopen the ticket and you should resolve it again when you've made the changes or have a response to our feedback. When we believe
@@ -134,14 +134,14 @@ The versioning for the Chef project is X.Y.Z.
134
134
  * Y is a minor release, which adds both new features and bug fixes
135
135
  * Z is a patch release, which adds just bug fixes
136
136
 
137
- Major releases and have historically been once a year. Minor releases for Chef average every two months and patch releases come as needed.
137
+ Major releases have historically been once a year. Minor releases for Chef average every three months and patch releases come as needed.
138
138
 
139
139
  There are usually beta releases and release candidates (RC) of major and minor releases announced on
140
140
  the [chef-dev mailing list](http://lists.opscode.com/sympa/info/chef-dev). Once an RC is released, we wait at least three
141
141
  days to allow for testing for regressions before the final release. If a blocking regression is found then another RC is made containing
142
142
  the fix and the timer is reset.
143
143
 
144
- Once the official release is made, the release notes are available on the [Opscode blog](http://www.opscode.com/blog).
144
+ Once the official release is made, the release notes are available on the [Chef blog](http://www.getchef.com/blog).
145
145
 
146
146
  ## Working with the community
147
147
 
@@ -151,5 +151,5 @@ These resources will help you learn more about Chef and connect to other members
151
151
  * #chef and #chef-hacking IRC channels on irc.freenode.net
152
152
  * [Community Cookbook site](http://community.opscode.com)
153
153
  * [Chef wiki](http://wiki.opscode.com/display/chef)
154
- * Opscode Chef [product page](http://www.opscode.com/chef)
154
+ * Chef [product page](http://www.getchef.com/chef)
155
155
 
data/README.md CHANGED
@@ -61,7 +61,7 @@ Then get the source and install it:
61
61
 
62
62
  Before working on the code, if you plan to contribute your changes, you need to
63
63
  read the
64
- [Opscode Contributing document](http://docs.opscode.com/community_contributions.html).
64
+ [Chef Contributions document](http://docs.opscode.com/community_contributions.html).
65
65
 
66
66
  You will also need to set up the repository with the appropriate branches. We
67
67
  document the process on the
@@ -162,9 +162,7 @@ class Chef
162
162
  if response.kind_of?(Chef::ApiClient)
163
163
  response
164
164
  else
165
- client = Chef::ApiClient.new
166
- client.name(response['clientname'])
167
- client
165
+ json_create(response)
168
166
  end
169
167
  end
170
168
 
@@ -208,7 +208,8 @@ class Chef::Application
208
208
  @chef_client = Chef::Client.new(
209
209
  @chef_client_json,
210
210
  :override_runlist => config[:override_runlist],
211
- :specific_recipes => specific_recipes
211
+ :specific_recipes => specific_recipes,
212
+ :runlist => config[:runlist]
212
213
  )
213
214
  @chef_client_json = nil
214
215
 
@@ -170,7 +170,7 @@ class Chef::Application::Client < Chef::Application
170
170
  option :override_runlist,
171
171
  :short => "-o RunlistItem,RunlistItem...",
172
172
  :long => "--override-runlist RunlistItem,RunlistItem...",
173
- :description => "Replace current run list with specified items",
173
+ :description => "Replace current run list with specified items for a single run",
174
174
  :proc => lambda{|items|
175
175
  items = items.split(',')
176
176
  items.compact.map{|item|
@@ -178,6 +178,16 @@ class Chef::Application::Client < Chef::Application
178
178
  }
179
179
  }
180
180
 
181
+ option :runlist,
182
+ :short => "-r RunlistItem,RunlistItem...",
183
+ :long => "--runlist RunlistItem,RunlistItem...",
184
+ :description => "Permanently replace current run list with specified items",
185
+ :proc => lambda{|items|
186
+ items = items.split(',')
187
+ items.compact.map{|item|
188
+ Chef::RunList::RunListItem.new(item)
189
+ }
190
+ }
181
191
  option :why_run,
182
192
  :short => '-W',
183
193
  :long => '--why-run',
@@ -44,6 +44,7 @@ require 'chef/version'
44
44
  require 'chef/resource_reporter'
45
45
  require 'chef/run_lock'
46
46
  require 'chef/policy_builder'
47
+ require 'chef/request_id'
47
48
  require 'ohai'
48
49
  require 'rbconfig'
49
50
 
@@ -54,6 +55,16 @@ class Chef
54
55
  class Client
55
56
  include Chef::Mixin::PathSanity
56
57
 
58
+ # IO stream that will be used as 'STDOUT' for formatters. Formatters are
59
+ # configured during `initialize`, so this provides a convenience for
60
+ # setting alternative IO stream during tests.
61
+ STDOUT_FD = STDOUT
62
+
63
+ # IO stream that will be used as 'STDERR' for formatters. Formatters are
64
+ # configured during `initialize`, so this provides a convenience for
65
+ # setting alternative IO stream during tests.
66
+ STDERR_FD = STDERR
67
+
57
68
  # Clears all notifications for client run status events.
58
69
  # Primarily for testing purposes.
59
70
  def self.clear_notifications
@@ -128,15 +139,13 @@ class Chef
128
139
  attr_accessor :rest
129
140
  attr_accessor :runner
130
141
 
131
- #--
132
- # TODO: timh/cw: 5-19-2010: json_attribs should be moved to RunContext?
133
142
  attr_reader :json_attribs
134
143
  attr_reader :run_status
135
144
  attr_reader :events
136
145
 
137
146
  # Creates a new Chef::Client.
138
147
  def initialize(json_attribs=nil, args={})
139
- @json_attribs = json_attribs
148
+ @json_attribs = json_attribs || {}
140
149
  @node = nil
141
150
  @run_status = nil
142
151
  @runner = nil
@@ -148,12 +157,16 @@ class Chef
148
157
  @events = EventDispatch::Dispatcher.new(*event_handlers)
149
158
  @override_runlist = args.delete(:override_runlist)
150
159
  @specific_recipes = args.delete(:specific_recipes)
160
+
161
+ if new_runlist = args.delete(:runlist)
162
+ @json_attribs["run_list"] = new_runlist
163
+ end
151
164
  end
152
165
 
153
166
  def configure_formatters
154
167
  formatters_for_run.map do |formatter_name, output_path|
155
168
  if output_path.nil?
156
- Chef::Formatters.new(formatter_name, STDOUT, STDERR)
169
+ Chef::Formatters.new(formatter_name, STDOUT_FD, STDERR_FD)
157
170
  else
158
171
  io = File.open(output_path, "a+")
159
172
  io.sync = true
@@ -280,13 +293,10 @@ class Chef
280
293
  end
281
294
 
282
295
  def node_name
283
- name = Chef::Config[:node_name] || ohai[:fqdn] || ohai[:hostname]
296
+ name = Chef::Config[:node_name] || ohai[:fqdn] || ohai[:machinename] || ohai[:hostname]
284
297
  Chef::Config[:node_name] = name
285
298
 
286
- unless name
287
- msg = "Unable to determine node name: configure node_name or configure the system's hostname and fqdn"
288
- raise Chef::Exceptions::CannotDetermineNodeName, msg
289
- end
299
+ raise Chef::Exceptions::CannotDetermineNodeName unless name
290
300
 
291
301
  # node names > 90 bytes only work with authentication protocol >= 1.1
292
302
  # see discussion in config.rb.
@@ -391,10 +401,12 @@ class Chef
391
401
  # don't add code that may fail before entering this section to be sure to release lock
392
402
  begin
393
403
  runlock.save_pid
404
+ request_id = Chef::RequestID.instance.request_id
394
405
  run_context = nil
395
406
  @events.run_start(Chef::VERSION)
396
407
  Chef::Log.info("*** Chef #{Chef::VERSION} ***")
397
408
  Chef::Log.info "Chef-client pid: #{Process.pid}"
409
+ Chef::Log.debug("Chef-client request_id: #{request_id}")
398
410
  enforce_path_sanity
399
411
  run_ohai
400
412
  @events.ohai_completed(node)
@@ -404,6 +416,7 @@ class Chef
404
416
 
405
417
  build_node
406
418
 
419
+ run_status.run_id = request_id
407
420
  run_status.start_clock
408
421
  Chef::Log.info("Starting Chef Run for #{node.name}")
409
422
  run_started
@@ -434,6 +447,8 @@ class Chef
434
447
  @events.run_failed(e)
435
448
  raise
436
449
  ensure
450
+ Chef::RequestID.instance.reset_request_id
451
+ request_id = nil
437
452
  @run_status = nil
438
453
  run_context = nil
439
454
  runlock.release
@@ -17,6 +17,8 @@
17
17
  #
18
18
 
19
19
  require 'pathname'
20
+ require 'stringio'
21
+ require 'erubis'
20
22
  require 'chef/mixin/shell_out'
21
23
  require 'chef/mixin/checksum'
22
24
 
@@ -161,28 +163,127 @@ class Chef
161
163
 
162
164
  def validate_template(erb_file)
163
165
  Chef::Log.debug("Testing template #{erb_file} for syntax errors...")
164
- result = shell_out("erubis -x #{erb_file} | ruby -c")
166
+ if validate_inline?
167
+ validate_erb_file_inline(erb_file)
168
+ else
169
+ validate_erb_via_subcommand(erb_file)
170
+ end
171
+ end
172
+
173
+ def validate_ruby_file(ruby_file)
174
+ Chef::Log.debug("Testing #{ruby_file} for syntax errors...")
175
+ if validate_inline?
176
+ validate_ruby_file_inline(ruby_file)
177
+ else
178
+ validate_ruby_by_subcommand(ruby_file)
179
+ end
180
+ end
181
+
182
+ # Whether or not we're running on a version of ruby that can support
183
+ # inline validation. Inline validation relies on the `RubyVM` features
184
+ # introduced with ruby 1.9, so 1.8 cannot be supported.
185
+ def validate_inline?
186
+ defined?(RubyVM::InstructionSequence)
187
+ end
188
+
189
+ # Validate the ruby code in an erb template. Uses RubyVM to do syntax
190
+ # checking, so callers should check #validate_inline? before calling.
191
+ def validate_erb_file_inline(erb_file)
192
+ old_stderr = $stderr
193
+
194
+ engine = Erubis::Eruby.new
195
+ engine.convert!(IO.read(erb_file))
196
+
197
+ ruby_code = engine.src
198
+
199
+ # Even when we're compiling the code w/ RubyVM, syntax errors just
200
+ # print to $stderr. We want to capture this and handle the printing
201
+ # ourselves, so we must temporarily swap $stderr to capture the output.
202
+ tmp_stderr = $stderr = StringIO.new
203
+
204
+ abs_path = File.expand_path(erb_file)
205
+ RubyVM::InstructionSequence.new(ruby_code, erb_file, abs_path, 0)
206
+
207
+ true
208
+ rescue SyntaxError
209
+ $stderr = old_stderr
210
+ invalid_erb_file(erb_file, tmp_stderr.string)
211
+ false
212
+ ensure
213
+ # be paranoid about setting stderr back to the old value.
214
+ $stderr = old_stderr if defined?(old_stderr) && old_stderr
215
+ end
216
+
217
+ # Validate the ruby code in an erb template. Pipes the output of `erubis
218
+ # -x` to `ruby -c`, so it works with any ruby version, but is much slower
219
+ # than the inline version.
220
+ # --
221
+ # TODO: This can be removed when ruby 1.8 support is dropped.
222
+ def validate_erb_via_subcommand(erb_file)
223
+ result = shell_out("erubis -x #{erb_file} | #{ruby} -c")
165
224
  result.error!
166
225
  true
167
226
  rescue Mixlib::ShellOut::ShellCommandFailed
227
+ invalid_erb_file(erb_file, result.stderr)
228
+ false
229
+ end
230
+
231
+ # Debug a syntax error in a template.
232
+ def invalid_erb_file(erb_file, error_message)
168
233
  file_relative_path = erb_file[/^#{Regexp.escape(cookbook_path+File::Separator)}(.*)/, 1]
169
234
  Chef::Log.fatal("Erb template #{file_relative_path} has a syntax error:")
170
- result.stderr.each_line { |l| Chef::Log.fatal(l.chomp) }
235
+ error_message.each_line { |l| Chef::Log.fatal(l.chomp) }
236
+ nil
237
+ end
238
+
239
+ # Validate the syntax of a ruby file. Uses (Ruby 1.9+ only) RubyVM to
240
+ # compile the code without evaluating it or spawning a new process.
241
+ # Callers should check #validate_inline? before calling.
242
+ def validate_ruby_file_inline(ruby_file)
243
+ # Even when we're compiling the code w/ RubyVM, syntax errors just
244
+ # print to $stderr. We want to capture this and handle the printing
245
+ # ourselves, so we must temporarily swap $stderr to capture the output.
246
+ old_stderr = $stderr
247
+ tmp_stderr = $stderr = StringIO.new
248
+ abs_path = File.expand_path(ruby_file)
249
+ file_content = IO.read(abs_path)
250
+ RubyVM::InstructionSequence.new(file_content, ruby_file, abs_path, 0)
251
+ true
252
+ rescue SyntaxError
253
+ $stderr = old_stderr
254
+ invalid_ruby_file(ruby_file, tmp_stderr.string)
171
255
  false
256
+ ensure
257
+ # be paranoid about setting stderr back to the old value.
258
+ $stderr = old_stderr if defined?(old_stderr) && old_stderr
172
259
  end
173
260
 
174
- def validate_ruby_file(ruby_file)
175
- Chef::Log.debug("Testing #{ruby_file} for syntax errors...")
176
- result = shell_out("ruby -c #{ruby_file}")
261
+ # Validate the syntax of a ruby file by shelling out to `ruby -c`. Should
262
+ # work for all ruby versions, but is slower and uses more resources than
263
+ # the inline strategy.
264
+ def validate_ruby_by_subcommand(ruby_file)
265
+ result = shell_out("#{ruby} -c #{ruby_file}")
177
266
  result.error!
178
267
  true
179
268
  rescue Mixlib::ShellOut::ShellCommandFailed
269
+ invalid_ruby_file(ruby_file, result.stderr)
270
+ false
271
+ end
272
+
273
+ # Debugs ruby syntax errors by printing the path to the file and any
274
+ # diagnostic info given in +error_message+
275
+ def invalid_ruby_file(ruby_file, error_message)
180
276
  file_relative_path = ruby_file[/^#{Regexp.escape(cookbook_path+File::Separator)}(.*)/, 1]
181
277
  Chef::Log.fatal("Cookbook file #{file_relative_path} has a ruby syntax error:")
182
- result.stderr.each_line { |l| Chef::Log.fatal(l.chomp) }
278
+ error_message.each_line { |l| Chef::Log.fatal(l.chomp) }
183
279
  false
184
280
  end
185
281
 
282
+ # Returns the full path to the running ruby.
283
+ def ruby
284
+ Gem.ruby
285
+ end
286
+
186
287
  end
187
288
  end
188
289
  end
@@ -0,0 +1,61 @@
1
+ # Author:: Bryan McLellan <btm@loftninjas.org>
2
+ # Author:: Seth Chisamore <schisamo@opscode.com>
3
+ # Copyright:: Copyright (c) 2011,2014, Chef Software, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'chef/dsl/platform_introspection'
20
+ require 'chef/dsl/registry_helper'
21
+
22
+ class Chef
23
+ module DSL
24
+ module RebootPending
25
+
26
+ include Chef::DSL::RegistryHelper
27
+ include Chef::DSL::PlatformIntrospection
28
+
29
+ # Returns true if the system needs a reboot or is expected to reboot
30
+ # Raises UnsupportedPlatform if this functionality isn't provided yet
31
+ def reboot_pending?
32
+
33
+ if platform?("windows")
34
+ # PendingFileRenameOperations contains pairs (REG_MULTI_SZ) of filenames that cannot be updated
35
+ # due to a file being in use (usually a temporary file and a system file)
36
+ # \??\c:\temp\test.sys!\??\c:\winnt\system32\test.sys
37
+ # http://technet.microsoft.com/en-us/library/cc960241.aspx
38
+ registry_value_exists?('HKLM\SYSTEM\CurrentControlSet\Control\Session Manager', { :name => 'PendingFileRenameOperations' }) ||
39
+
40
+ # RebootRequired key contains Update IDs with a value of 1 if they require a reboot.
41
+ # The existence of RebootRequired alone is sufficient on my Windows 8.1 workstation in Windows Update
42
+ registry_key_exists?('HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired') ||
43
+
44
+ # Vista + Server 2008 and newer may have reboots pending from CBS
45
+ registry_key_exists?('HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootRequired') ||
46
+
47
+ # The mere existance of the UpdateExeVolatile key should indicate a pending restart for certain updates
48
+ # http://support.microsoft.com/kb/832475
49
+ (registry_key_exists?('HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile') &&
50
+ !registry_get_values('HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile').select { |v| v[:name] == "Flags" }[0].nil? &&
51
+ [1,2,3].include?(registry_get_values('HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile').select { |v| v[:name] == "Flags" }[0][:data]))
52
+ elsif platform?("ubuntu")
53
+ # This should work for Debian as well if update-notifier-common happens to be installed. We need an API for that.
54
+ File.exists?('/var/run/reboot-required')
55
+ else
56
+ raise Chef::Exceptions::UnsupportedPlatform.new(node[:platform])
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -50,7 +50,13 @@ class Chef
50
50
  class Override < RuntimeError; end
51
51
  class UnsupportedAction < RuntimeError; end
52
52
  class MissingLibrary < RuntimeError; end
53
- class CannotDetermineNodeName < RuntimeError; end
53
+
54
+ class CannotDetermineNodeName < RuntimeError
55
+ def initialize
56
+ super "Unable to determine node name: configure node_name or configure the system's hostname and fqdn"
57
+ end
58
+ end
59
+
54
60
  class User < RuntimeError; end
55
61
  class Group < RuntimeError; end
56
62
  class Link < RuntimeError; end
@@ -309,5 +315,10 @@ class Chef
309
315
  end
310
316
  end
311
317
 
318
+ class UnsupportedPlatform < RuntimeError
319
+ def initialize(platform)
320
+ super "This functionality is not supported on platform #{platform}."
321
+ end
322
+ end
312
323
  end
313
324
  end