chef 11.2.0 → 11.4.0.rc.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) 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-shell.1.html +7 -7
  7. data/distro/common/html/chef-solo.8.html +3 -3
  8. data/distro/common/html/chef-solr.8.html +3 -3
  9. data/distro/common/html/knife-bootstrap.1.html +4 -4
  10. data/distro/common/html/knife-client.1.html +3 -3
  11. data/distro/common/html/knife-configure.1.html +3 -3
  12. data/distro/common/html/knife-cookbook-site.1.html +3 -3
  13. data/distro/common/html/knife-cookbook.1.html +3 -3
  14. data/distro/common/html/knife-data-bag.1.html +3 -3
  15. data/distro/common/html/knife-environment.1.html +6 -6
  16. data/distro/common/html/knife-exec.1.html +4 -4
  17. data/distro/common/html/knife-index.1.html +4 -4
  18. data/distro/common/html/knife-node.1.html +3 -3
  19. data/distro/common/html/knife-role.1.html +6 -6
  20. data/distro/common/html/knife-search.1.html +3 -3
  21. data/distro/common/html/knife-ssh.1.html +4 -4
  22. data/distro/common/html/knife-status.1.html +4 -4
  23. data/distro/common/html/knife-tag.1.html +4 -4
  24. data/distro/common/html/knife.1.html +3 -3
  25. data/distro/common/man/man1/chef-shell.1 +1 -1
  26. data/distro/common/man/man1/knife-bootstrap.1 +1 -1
  27. data/distro/common/man/man1/knife-client.1 +1 -1
  28. data/distro/common/man/man1/knife-configure.1 +1 -1
  29. data/distro/common/man/man1/knife-cookbook-site.1 +1 -1
  30. data/distro/common/man/man1/knife-cookbook.1 +1 -1
  31. data/distro/common/man/man1/knife-data-bag.1 +1 -1
  32. data/distro/common/man/man1/knife-environment.1 +1 -1
  33. data/distro/common/man/man1/knife-exec.1 +1 -1
  34. data/distro/common/man/man1/knife-index.1 +1 -1
  35. data/distro/common/man/man1/knife-node.1 +1 -1
  36. data/distro/common/man/man1/knife-role.1 +1 -1
  37. data/distro/common/man/man1/knife-search.1 +1 -1
  38. data/distro/common/man/man1/knife-ssh.1 +1 -1
  39. data/distro/common/man/man1/knife-status.1 +1 -1
  40. data/distro/common/man/man1/knife-tag.1 +1 -1
  41. data/distro/common/man/man1/knife.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/cookbook_version.rb +1 -1
  50. data/lib/chef/data_bag.rb +1 -1
  51. data/lib/chef/json_compat.rb +95 -1
  52. data/lib/chef/resource.rb +17 -0
  53. data/lib/chef/version.rb +1 -1
  54. data/lib/chef/win32/api/process.rb +1 -0
  55. data/lib/chef/win32/handle.rb +8 -1
  56. data/spec/functional/run_lock_spec.rb +145 -31
  57. data/spec/unit/knife/user_create_spec.rb +1 -1
  58. metadata +26 -36
@@ -129,6 +129,23 @@ F
129
129
 
130
130
  extend Chef::Mixin::ConvertToClassName
131
131
 
132
+ # Track all subclasses of Resource. This is used so names can be looked up
133
+ # when attempting to deserialize from JSON. (See: json_compat)
134
+ def self.resource_classes
135
+ @resource_classes ||= []
136
+ end
137
+
138
+ # Callback when subclass is defined. Adds subclass to list of subclasses.
139
+ def self.inherited(subclass)
140
+ resource_classes << subclass
141
+ end
142
+
143
+ # Look up a subclass by +class_name+ which should be a string that matches
144
+ # `Subclass.name`
145
+ def self.find_subclass_by_name(class_name)
146
+ resource_classes.first {|c| c.name == class_name }
147
+ end
148
+
132
149
  # Set or return the list of "state attributes" implemented by the Resource
133
150
  # subclass. State attributes are attributes that describe the desired state
134
151
  # of the system, such as file permissions or ownership. In general, state
@@ -17,7 +17,7 @@
17
17
 
18
18
  class Chef
19
19
  CHEF_ROOT = File.dirname(File.expand_path(File.dirname(__FILE__)))
20
- VERSION = '11.2.0'
20
+ VERSION = '11.4.0.rc.0'
21
21
  end
22
22
 
23
23
  # NOTE: the Chef::Version class is defined in version_class.rb
@@ -33,6 +33,7 @@ class Chef
33
33
  safe_attach_function :GetCurrentProcess, [], :HANDLE
34
34
  safe_attach_function :GetProcessHandleCount, [ :HANDLE, :LPDWORD ], :BOOL
35
35
  safe_attach_function :GetProcessId, [ :HANDLE ], :DWORD
36
+ safe_attach_function :CloseHandle, [ :HANDLE ], :BOOL
36
37
 
37
38
  end
38
39
  end
@@ -26,6 +26,10 @@ class Chef
26
26
  class Handle
27
27
  extend Chef::ReservedNames::Win32::API::Process
28
28
 
29
+ # See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683179(v=vs.85).aspx
30
+ # The handle value returned by the GetCurrentProcess function is the pseudo handle (HANDLE)-1 (which is 0xFFFFFFFF)
31
+ CURRENT_PROCESS_HANDLE = 4294967295
32
+
29
33
  def initialize(handle)
30
34
  @handle = handle
31
35
  ObjectSpace.define_finalizer(self, Handle.close_handle_finalizer(handle))
@@ -34,7 +38,10 @@ class Chef
34
38
  attr_reader :handle
35
39
 
36
40
  def self.close_handle_finalizer(handle)
37
- proc { close_handle(handle) }
41
+ # According to http://msdn.microsoft.com/en-us/library/windows/desktop/ms683179(v=vs.85).aspx, it is not necessary
42
+ # to close the pseudo handle returned by the GetCurrentProcess function. The docs also say that it doesn't hurt to call
43
+ # CloseHandle on it. However, doing so from inside of Ruby always seems to produce an invalid handle error.
44
+ proc { close_handle(handle) unless handle == CURRENT_PROCESS_HANDLE }
38
45
  end
39
46
 
40
47
  def self.close_handle(handle)
@@ -22,6 +22,10 @@ describe Chef::RunLock do
22
22
 
23
23
  # This behavior is believed to work on windows, but the tests use UNIX APIs.
24
24
  describe "when locking the chef-client run", :unix_only => true do
25
+
26
+ ##
27
+ # Lockfile location and helpers
28
+
25
29
  let(:random_temp_root) do
26
30
  Kernel.srand(Time.now.to_i + Process.pid)
27
31
  "/tmp/#{Kernel.rand(Time.now.to_i + Process.pid)}"
@@ -32,73 +36,183 @@ describe Chef::RunLock do
32
36
 
33
37
  after(:each){ FileUtils.rm_r(random_temp_root) }
34
38
 
39
+ def wait_on_lock
40
+ tries = 0
41
+ until File.exist?(lockfile)
42
+ raise "Lockfile never created, abandoning test" if tries > 10
43
+ tries += 1
44
+ sleep 0.1
45
+ end
46
+ end
47
+
48
+ ##
49
+ # Side channel via a pipe allows child processes to send errors to the parent
50
+
51
+ # Don't lazy create the pipe or else we might not share it with subprocesses
52
+ let!(:error_pipe) { IO.pipe }
53
+ let(:error_read) { error_pipe[0] }
54
+ let(:error_write) { error_pipe[1] }
55
+
56
+ after do
57
+ error_read.close unless error_read.closed?
58
+ error_write.close unless error_write.closed?
59
+ end
60
+
61
+ # Send a RuntimeError from the child process to the parent process. Also
62
+ # prints error to $stdout, just in case something goes wrong with the error
63
+ # marshaling stuff.
64
+ def send_side_channel_error(message)
65
+ $stderr.puts(message)
66
+ $stderr.puts(caller)
67
+ e = RuntimeError.new(message)
68
+ error_write.print(Marshal.dump(e))
69
+ end
70
+
71
+ # Read the error (if any) from the error channel. If a marhaled error is
72
+ # present, it is unmarshaled and raised (which will fail the test)
73
+ def raise_side_channel_error!
74
+ error_write.close
75
+ err = error_read.read
76
+ error_read.close
77
+ begin
78
+ # ArgumentError from Marshal.load indicates no data, which we assume
79
+ # means no error in child process.
80
+ raise Marshal.load(err)
81
+ rescue ArgumentError
82
+ nil
83
+ end
84
+ end
85
+
86
+ ##
87
+ # Interprocess synchronization via a pipe. This allows us to control the
88
+ # state of the processes competing over the lock without relying on sleep.
89
+
90
+ let!(:sync_pipe) { IO.pipe }
91
+ let(:sync_read) { sync_pipe[0] }
92
+ let(:sync_write) { sync_pipe[1] }
93
+
94
+ after do
95
+ sync_read.close unless sync_read.closed?
96
+ sync_write.close unless sync_write.closed?
97
+ end
98
+
99
+ # Wait on synchronization signal. If not received within the timeout, an
100
+ # error is sent via the error channel, and the process exits.
101
+ def sync_wait
102
+ if IO.select([sync_read], nil, nil, 20).nil?
103
+ # timeout reading from the sync pipe.
104
+ send_side_channel_error("Error syncing processes in run lock test (timeout)")
105
+ exit!(1)
106
+ end
107
+ end
108
+
109
+ # Sends a character in the sync pipe, which wakes ("unlocks") another
110
+ # process that is waiting on the sync signal
111
+ def sync_send
112
+ sync_write.putc("!")
113
+ end
114
+
115
+ ##
116
+ # IPC to record test results in a pipe. Tests can read pipe contents to
117
+ # check that operations occur in the expected order.
118
+
119
+ let!(:results_pipe) { IO.pipe }
120
+ let(:results_read) { results_pipe[0] }
121
+ let(:results_write) { results_pipe[1] }
122
+
123
+ after do
124
+ results_read.close unless results_read.closed?
125
+ results_write.close unless results_write.closed?
126
+ end
127
+
128
+ # writes the message to the results pipe for later checking.
129
+ # note that nothing accounts for the pipe filling and waiting forever on a
130
+ # read or write call, so don't put too much data in.
131
+ def record(message)
132
+ results_write.puts(message)
133
+ end
134
+
135
+ def results
136
+ results_write.close
137
+ message = results_read.read
138
+ results_read.close
139
+ message
140
+ end
141
+
142
+ ##
143
+ # Run lock is the system under test
144
+ let!(:run_lock) { Chef::RunLock.new(:file_cache_path => file_cache_path, :lockfile => lockfile) }
145
+
35
146
  it "creates the full path to the lockfile" do
36
- run_lock = Chef::RunLock.new(:file_cache_path => file_cache_path, :lockfile => lockfile)
37
147
  lambda { run_lock.acquire }.should_not raise_error(Errno::ENOENT)
38
148
  File.should exist(lockfile)
39
149
  end
40
150
 
41
151
  it "allows only one chef client run per lockfile" do
42
- read, write = IO.pipe
43
- run_lock = Chef::RunLock.new(:file_cache_path => file_cache_path, :lockfile => lockfile)
152
+ # First process, gets the lock and keeps it.
44
153
  p1 = fork do
45
154
  run_lock.acquire
46
- write.puts 1
47
- #puts "[#{Time.new.to_i % 100}] p1 (#{Process.pid}) running with lock"
155
+ record "p1 has lock"
156
+ # Wait until the other process is trying to get the lock:
157
+ sync_wait
158
+ # sleep a little bit to make process p2 wait on the lock
48
159
  sleep 2
49
- write.puts 2
50
- #puts "[#{Time.new.to_i % 100}] p1 (#{Process.pid}) releasing lock"
160
+ record "p1 releasing lock"
51
161
  run_lock.release
162
+ exit!(0)
52
163
  end
53
164
 
54
- sleep 0.5
165
+ # Wait until p1 creates the lockfile
166
+ wait_on_lock
55
167
 
56
168
  p2 = fork do
169
+ # inform process p1 that we're trying to get the lock
170
+ sync_send
171
+ record "p2 requesting lock"
57
172
  run_lock.acquire
58
- write.puts 3
59
- #puts "[#{Time.new.to_i % 100}] p2 (#{Process.pid}) running with lock"
173
+ record "p2 has lock"
60
174
  run_lock.release
175
+ exit!(0)
61
176
  end
62
177
 
63
178
  Process.waitpid2(p1)
64
179
  Process.waitpid2(p2)
65
180
 
66
- write.close
67
- order = read.read
68
- read.close
181
+ raise_side_channel_error!
69
182
 
70
- order.should == "1\n2\n3\n"
183
+ expected=<<-E
184
+ p1 has lock
185
+ p2 requesting lock
186
+ p1 releasing lock
187
+ p2 has lock
188
+ E
189
+ results.should == expected
71
190
  end
72
191
 
73
192
  it "clears the lock if the process dies unexpectedly" do
74
- read, write = IO.pipe
75
- run_lock = Chef::RunLock.new(:file_cache_path => file_cache_path, :lockfile => lockfile)
76
193
  p1 = fork do
77
194
  run_lock.acquire
78
- write.puts 1
79
- #puts "[#{Time.new.to_i % 100}] p1 (#{Process.pid}) running with lock"
80
- sleep 1
81
- write.puts 2
82
- #puts "[#{Time.new.to_i % 100}] p1 (#{Process.pid}) releasing lock"
83
- run_lock.release
195
+ record "p1 has lock"
196
+ sleep 60
197
+ record "p1 still has lock"
198
+ exit! 1
84
199
  end
85
200
 
201
+ wait_on_lock
202
+ Process.kill(:KILL, p1)
203
+ Process.waitpid2(p1)
204
+
205
+
86
206
  p2 = fork do
87
207
  run_lock.acquire
88
- write.puts 3
89
- #puts "[#{Time.new.to_i % 100}] p2 (#{Process.pid}) running with lock"
208
+ record "p2 has lock"
90
209
  run_lock.release
210
+ exit! 0
91
211
  end
92
- Process.kill(:KILL, p1)
93
212
 
94
- Process.waitpid2(p1)
95
213
  Process.waitpid2(p2)
96
214
 
97
- write.close
98
- order = read.read
99
- read.close
100
-
101
- order.should =~ /3\Z/
215
+ results.should =~ /p2 has lock\Z/
102
216
  end
103
217
  end
104
218
 
@@ -66,7 +66,7 @@ describe Chef::Knife::UserCreate do
66
66
 
67
67
  it "sets the public key if given" do
68
68
  @knife.config[:user_key] = "/a/filename"
69
- File.stub(:read).with("/a/filename").and_return("a_key")
69
+ File.stub(:read).with(File.expand_path("/a/filename")).and_return("a_key")
70
70
  @user.should_receive(:public_key).with("a_key")
71
71
  @knife.run
72
72
  end
metadata CHANGED
@@ -1,13 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chef
3
3
  version: !ruby/object:Gem::Version
4
- hash: 79
5
- prerelease:
4
+ hash: 1142537593
5
+ prerelease: 7
6
6
  segments:
7
7
  - 11
8
- - 2
8
+ - 4
9
9
  - 0
10
- version: 11.2.0
10
+ - rc
11
+ - 0
12
+ version: 11.4.0.rc.0
11
13
  platform: ruby
12
14
  authors:
13
15
  - Adam Jacob
@@ -15,7 +17,7 @@ autorequire:
15
17
  bindir: bin
16
18
  cert_chain: []
17
19
 
18
- date: 2013-02-06 00:00:00 Z
20
+ date: 2013-02-12 00:00:00 Z
19
21
  dependencies:
20
22
  - !ruby/object:Gem::Dependency
21
23
  name: mixlib-config
@@ -149,14 +151,14 @@ dependencies:
149
151
  - 4
150
152
  - 4
151
153
  version: 1.4.4
152
- - - ~>
154
+ - - <=
153
155
  - !ruby/object:Gem::Version
154
- hash: 7
156
+ hash: 5
155
157
  segments:
156
158
  - 1
157
159
  - 7
158
- - 6
159
- version: 1.7.6
160
+ - 7
161
+ version: 1.7.7
160
162
  type: :runtime
161
163
  version_requirements: *id008
162
164
  - !ruby/object:Gem::Dependency
@@ -264,7 +266,7 @@ dependencies:
264
266
  type: :development
265
267
  version_requirements: *id015
266
268
  - !ruby/object:Gem::Dependency
267
- name: ronn
269
+ name: rake
268
270
  prerelease: false
269
271
  requirement: &id016 !ruby/object:Gem::Requirement
270
272
  none: false
@@ -278,7 +280,7 @@ dependencies:
278
280
  type: :development
279
281
  version_requirements: *id016
280
282
  - !ruby/object:Gem::Dependency
281
- name: rake
283
+ name: rack
282
284
  prerelease: false
283
285
  requirement: &id017 !ruby/object:Gem::Requirement
284
286
  none: false
@@ -292,7 +294,7 @@ dependencies:
292
294
  type: :development
293
295
  version_requirements: *id017
294
296
  - !ruby/object:Gem::Dependency
295
- name: rack
297
+ name: rspec_junit_formatter
296
298
  prerelease: false
297
299
  requirement: &id018 !ruby/object:Gem::Requirement
298
300
  none: false
@@ -305,24 +307,10 @@ dependencies:
305
307
  version: "0"
306
308
  type: :development
307
309
  version_requirements: *id018
308
- - !ruby/object:Gem::Dependency
309
- name: rspec_junit_formatter
310
- prerelease: false
311
- requirement: &id019 !ruby/object:Gem::Requirement
312
- none: false
313
- requirements:
314
- - - ">="
315
- - !ruby/object:Gem::Version
316
- hash: 3
317
- segments:
318
- - 0
319
- version: "0"
320
- type: :development
321
- version_requirements: *id019
322
310
  - !ruby/object:Gem::Dependency
323
311
  name: rspec-core
324
312
  prerelease: false
325
- requirement: &id020 !ruby/object:Gem::Requirement
313
+ requirement: &id019 !ruby/object:Gem::Requirement
326
314
  none: false
327
315
  requirements:
328
316
  - - ~>
@@ -334,11 +322,11 @@ dependencies:
334
322
  - 0
335
323
  version: 2.12.0
336
324
  type: :development
337
- version_requirements: *id020
325
+ version_requirements: *id019
338
326
  - !ruby/object:Gem::Dependency
339
327
  name: rspec-expectations
340
328
  prerelease: false
341
- requirement: &id021 !ruby/object:Gem::Requirement
329
+ requirement: &id020 !ruby/object:Gem::Requirement
342
330
  none: false
343
331
  requirements:
344
332
  - - ~>
@@ -350,11 +338,11 @@ dependencies:
350
338
  - 0
351
339
  version: 2.12.0
352
340
  type: :development
353
- version_requirements: *id021
341
+ version_requirements: *id020
354
342
  - !ruby/object:Gem::Dependency
355
343
  name: rspec-mocks
356
344
  prerelease: false
357
- requirement: &id022 !ruby/object:Gem::Requirement
345
+ requirement: &id021 !ruby/object:Gem::Requirement
358
346
  none: false
359
347
  requirements:
360
348
  - - ~>
@@ -366,7 +354,7 @@ dependencies:
366
354
  - 0
367
355
  version: 2.12.0
368
356
  type: :development
369
- version_requirements: *id022
357
+ version_requirements: *id021
370
358
  description: A systems integration framework, built to bring the benefits of configuration management to your entire infrastructure.
371
359
  email: adam@opscode.com
372
360
  executables:
@@ -1478,12 +1466,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
1478
1466
  required_rubygems_version: !ruby/object:Gem::Requirement
1479
1467
  none: false
1480
1468
  requirements:
1481
- - - ">="
1469
+ - - ">"
1482
1470
  - !ruby/object:Gem::Version
1483
- hash: 3
1471
+ hash: 25
1484
1472
  segments:
1485
- - 0
1486
- version: "0"
1473
+ - 1
1474
+ - 3
1475
+ - 1
1476
+ version: 1.3.1
1487
1477
  requirements: []
1488
1478
 
1489
1479
  rubyforge_project: