vagabond 0.2.0 → 0.2.2

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 (73) hide show
  1. data/CHANGELOG.md +18 -0
  2. data/README.md +125 -4
  3. data/bin/vagabond +43 -16
  4. data/lib/vagabond/actions/cluster.rb +66 -0
  5. data/lib/vagabond/actions/create.rb +12 -7
  6. data/lib/vagabond/actions/destroy.rb +69 -15
  7. data/lib/vagabond/actions/init.rb +75 -0
  8. data/lib/vagabond/actions/provision.rb +4 -2
  9. data/lib/vagabond/actions/status.rb +33 -22
  10. data/lib/vagabond/actions/up.rb +8 -1
  11. data/lib/vagabond/bootstraps/server-zero.erb +20 -0
  12. data/lib/vagabond/bootstraps/server.erb +3 -2
  13. data/lib/vagabond/constants.rb +0 -15
  14. data/lib/vagabond/cookbooks/lxc/CHANGELOG.md +16 -0
  15. data/lib/vagabond/cookbooks/lxc/Gemfile +3 -2
  16. data/lib/vagabond/cookbooks/lxc/Gemfile.lock +30 -121
  17. data/lib/vagabond/cookbooks/lxc/README.md +43 -14
  18. data/lib/vagabond/cookbooks/lxc/attributes/default.rb +3 -3
  19. data/lib/vagabond/cookbooks/lxc/files/default/lxc-awesome-ephemeral +499 -0
  20. data/lib/vagabond/cookbooks/lxc/libraries/lxc.rb +223 -58
  21. data/lib/vagabond/cookbooks/lxc/libraries/lxc_file_config.rb +3 -0
  22. data/lib/vagabond/cookbooks/lxc/libraries/monkey.rb +51 -0
  23. data/lib/vagabond/cookbooks/lxc/metadata.rb +6 -5
  24. data/lib/vagabond/cookbooks/lxc/providers/config.rb +9 -16
  25. data/lib/vagabond/cookbooks/lxc/providers/container.rb +241 -229
  26. data/lib/vagabond/cookbooks/lxc/providers/default.rb +57 -0
  27. data/lib/vagabond/cookbooks/lxc/providers/ephemeral.rb +40 -0
  28. data/lib/vagabond/cookbooks/lxc/providers/fstab.rb +13 -54
  29. data/lib/vagabond/cookbooks/lxc/providers/interface.rb +13 -67
  30. data/lib/vagabond/cookbooks/lxc/providers/service.rb +14 -14
  31. data/lib/vagabond/cookbooks/lxc/recipes/default.rb +17 -4
  32. data/lib/vagabond/cookbooks/lxc/recipes/install_dependencies.rb +1 -1
  33. data/lib/vagabond/cookbooks/lxc/resources/config.rb +2 -2
  34. data/lib/vagabond/cookbooks/lxc/resources/container.rb +31 -6
  35. data/lib/vagabond/cookbooks/lxc/resources/default.rb +12 -0
  36. data/lib/vagabond/cookbooks/lxc/resources/ephemeral.rb +13 -0
  37. data/lib/vagabond/cookbooks/lxc/resources/fstab.rb +2 -1
  38. data/lib/vagabond/cookbooks/lxc/resources/interface.rb +6 -3
  39. data/lib/vagabond/cookbooks/lxc/resources/service.rb +1 -1
  40. data/lib/vagabond/cookbooks/lxc/templates/default/file_content.erb +2 -0
  41. data/lib/vagabond/cookbooks/lxc/templates/default/interface.erb +9 -3
  42. data/lib/vagabond/cookbooks/vagabond/README.md +10 -0
  43. data/lib/vagabond/cookbooks/vagabond/attributes/default.rb +1 -0
  44. data/lib/vagabond/cookbooks/vagabond/files/default/lxc-centos +13 -6
  45. data/lib/vagabond/cookbooks/vagabond/metadata.rb +1 -0
  46. data/lib/vagabond/cookbooks/vagabond/recipes/default.rb +46 -4
  47. data/lib/vagabond/cookbooks/vagabond/recipes/zero.rb +9 -0
  48. data/lib/vagabond/errors.rb +23 -0
  49. data/lib/vagabond/helpers.rb +41 -14
  50. data/lib/vagabond/internal_configuration.rb +120 -27
  51. data/lib/vagabond/kitchen.rb +143 -63
  52. data/lib/vagabond/knife.rb +8 -5
  53. data/lib/vagabond/layout.rb +16 -0
  54. data/lib/vagabond/monkey/kitchen_config.rb +23 -0
  55. data/lib/vagabond/server.rb +79 -63
  56. data/lib/vagabond/spec.rb +345 -0
  57. data/lib/vagabond/uploader.rb +30 -0
  58. data/lib/vagabond/uploader/berkshelf.rb +53 -0
  59. data/lib/vagabond/uploader/knife.rb +24 -0
  60. data/lib/vagabond/uploader/librarian.rb +31 -0
  61. data/lib/vagabond/vagabond.rb +30 -11
  62. data/lib/vagabond/vagabondfile.rb +40 -5
  63. data/lib/vagabond/version.rb +1 -1
  64. data/vagabond.gemspec +5 -2
  65. metadata +75 -15
  66. data/lib/vagabond/cookbooks/lxc/resources/#container.rb# +0 -28
  67. data/lib/vagabond/cookbooks/lxc/test/kitchen/Kitchenfile +0 -7
  68. data/lib/vagabond/cookbooks/lxc/test/kitchen/cookbooks/lxc_test/metadata.rb +0 -2
  69. data/lib/vagabond/cookbooks/lxc/test/kitchen/cookbooks/lxc_test/recipes/centos_lxc.rb +0 -0
  70. data/lib/vagabond/cookbooks/lxc/test/kitchen/cookbooks/lxc_test/recipes/chef-bootstrap.rb +0 -0
  71. data/lib/vagabond/cookbooks/lxc/test/kitchen/cookbooks/lxc_test/recipes/lxc_files.rb +0 -0
  72. data/lib/vagabond/cookbooks/lxc/test/kitchen/cookbooks/lxc_test/recipes/lxc_templates.rb +0 -0
  73. data/lib/vagabond/cookbooks/lxc/test/kitchen/cookbooks/lxc_test/recipes/ubuntu_lxc.rb +0 -0
@@ -1,12 +1,95 @@
1
+ require 'mixlib/shellout'
2
+ require 'pathname'
3
+ require 'tmpdir'
4
+
1
5
  class Lxc
2
6
  class CommandFailed < StandardError
3
7
  end
8
+
9
+ module Helpers
10
+
11
+ # Simple helper to shell out
12
+ def run_command(cmd, args={})
13
+ retries = args[:allow_failure_retry].to_i
14
+ begin
15
+ shlout = Mixlib::ShellOut.new(cmd,
16
+ :logger => defined?(Chef::Log) ? Chef::Log.logger : log,
17
+ :live_stream => args[:livestream] ? STDOUT : nil,
18
+ :timeout => args[:timeout] || 1200,
19
+ :environment => {'HOME' => detect_home}
20
+ )
21
+ shlout.run_command
22
+ shlout.error!
23
+ shlout
24
+ rescue Mixlib::ShellOut::ShellCommandFailed, CommandFailed, Mixlib::ShellOut::CommandTimeout
25
+ if(retries > 0)
26
+ log.warn "LXC run command failed: #{cmd}"
27
+ log.warn "Retrying command. #{args[:allow_failure_retry].to_i - retries} of #{args[:allow_failure_retry].to_i} retries remain"
28
+ sleep(0.3)
29
+ retries -= 1
30
+ retry
31
+ elsif(args[:allow_failure])
32
+ true
33
+ else
34
+ raise
35
+ end
36
+ end
37
+ end
38
+
39
+ def command(*args)
40
+ run_command(*args)
41
+ end
42
+
43
+ def log
44
+ if(defined?(Chef::Log))
45
+ Chef::Log
46
+ else
47
+ unless(@logger)
48
+ require 'logger'
49
+ @logger = Logger.new('/dev/null')
50
+ end
51
+ @logger
52
+ end
53
+ end
54
+
55
+ # Detect HOME environment variable. If not an acceptable
56
+ # value, set to /root or /tmp
57
+ def detect_home(set_if_missing=false)
58
+ if(ENV['HOME'] && Pathname.new(ENV['HOME']).absolute?)
59
+ ENV['HOME']
60
+ else
61
+ home = File.directory?('/root') && File.writable?('/root') ? '/root' : '/tmp'
62
+ if(set_if_missing)
63
+ ENV['HOME'] = home
64
+ end
65
+ home
66
+ end
67
+ end
68
+ end
69
+
70
+ # Pathname#join does not act like File#join when joining paths that
71
+ # begin with '/', and that's dumb. So we'll make our own Pathname,
72
+ # with a #join that uses File
73
+ class Pathname < ::Pathname
74
+ def join(*args)
75
+ self.class.new(::File.join(self.to_path, *args))
76
+ end
77
+ end
4
78
 
5
- attr_reader :name
79
+ include Helpers
80
+
81
+ attr_reader :name, :base_path, :lease_file, :preferred_device
6
82
 
7
83
  class << self
8
84
 
85
+ include Helpers
86
+
9
87
  attr_accessor :use_sudo
88
+ attr_accessor :base_path
89
+
90
+ def base_path
91
+ @base_path || '/var/lib/lxc'
92
+ end
10
93
 
11
94
  def sudo
12
95
  case use_sudo
@@ -40,19 +123,28 @@ class Lxc
40
123
 
41
124
  # List of containers
42
125
  def list
43
- %x{#{sudo}lxc-ls}.split("\n").uniq
126
+ Dir.glob(File.join(base_path, '*')).map do |item|
127
+ if(File.directory?(item) && File.exists?(File.join(item, 'config')))
128
+ File.basename(item)
129
+ end
130
+ end.compact
44
131
  end
45
-
132
+
46
133
  # name:: Name of container
47
134
  # Returns information about given container
48
135
  def info(name)
49
136
  res = {:state => nil, :pid => nil}
50
- info = %x{#{sudo}lxc-info -n #{name}}.split("\n")
51
- parts = info.first.split(' ')
52
- res[:state] = parts.last.downcase.to_sym
53
- parts = info.last.split(' ')
54
- res[:pid] = parts.last.to_i
55
- res
137
+ info = run_command("#{sudo}lxc-info -n #{name}").stdout.split("\n")
138
+ if(info.first)
139
+ parts = info.first.split(' ')
140
+ res[:state] = parts.last.downcase.to_sym
141
+ parts = info.last.split(' ')
142
+ res[:pid] = parts.last.to_i
143
+ res
144
+ else
145
+ res[:state] = :unknown
146
+ res[:pid] = -1
147
+ end
56
148
  end
57
149
 
58
150
  # Return full container information list
@@ -78,10 +170,12 @@ class Lxc
78
170
  # args:: Argument hash
79
171
  # - :base_path -> path to container directory
80
172
  # - :dnsmasq_lease_file -> path to lease file
173
+ # - :net_device -> network device to use within container for ssh connection
81
174
  def initialize(name, args={})
82
175
  @name = name
83
- @base_path = args[:base_path] || '/var/lib/lxc'
176
+ @base_path = args[:base_path] || self.class.base_path
84
177
  @lease_file = args[:dnsmasq_lease_file] || '/var/lib/misc/dnsmasq.leases'
178
+ @preferred_device = args[:net_device]
85
179
  end
86
180
 
87
181
  # Returns if container exists
@@ -109,8 +203,20 @@ class Lxc
109
203
  def container_ip(retries=0, raise_on_fail=false)
110
204
  (retries.to_i + 1).times do
111
205
  ip = proc_detected_address || hw_detected_address || leased_address || lxc_stored_address
206
+ if(ip.is_a?(Array))
207
+ # Filter any found loopbacks
208
+ ip.delete_if{|info| info[:device].start_with?('lo') }
209
+ ip = ip.detect do |info|
210
+ if(@preferred_device)
211
+ info[:device] == @preferred_device
212
+ else
213
+ true
214
+ end
215
+ end
216
+ ip = ip[:address] if ip
217
+ end
112
218
  return ip if ip && self.class.connection_alive?(ip)
113
- Chef::Log.warn "LXC IP discovery: Failed to detect live IP"
219
+ log.warn "LXC IP discovery: Failed to detect live IP"
114
220
  sleep(3) if retries > 0
115
221
  end
116
222
  raise "Failed to detect live IP address for container: #{name}" if raise_on_fail
@@ -125,7 +231,7 @@ class Lxc
125
231
  if(ip.to_s.empty?)
126
232
  nil
127
233
  else
128
- Chef::Log.info "LXC Discovery: Found container address via storage: #{ip}"
234
+ log.info "LXC Discovery: Found container address via storage: #{ip}"
129
235
  ip
130
236
  end
131
237
  end
@@ -145,25 +251,27 @@ class Lxc
145
251
  if(ip.to_s.empty?)
146
252
  nil
147
253
  else
148
- Chef::Log.info "LXC Discovery: Found container address via DHCP lease: #{ip}"
254
+ log.info "LXC Discovery: Found container address via DHCP lease: #{ip}"
149
255
  ip
150
256
  end
151
257
  end
152
258
 
153
259
  def hw_detected_address
154
- hw = File.readlines(container_config).detect{|line|
155
- line.include?('hwaddr')
156
- }.to_s.split('=').last.to_s.downcase
157
- if(File.exists?(container_config) && !hw.empty?)
158
- running? # need to do a list!
159
- ip = File.readlines('/proc/net/arp').detect{|line|
160
- line.downcase.include?(hw)
161
- }.to_s.split(' ').first.to_s.strip
162
- if(ip.to_s.empty?)
163
- nil
164
- else
165
- Chef::Log.info "LXC Discovery: Found container address via HW addr: #{ip}"
166
- ip
260
+ if(container_config.readable?)
261
+ hw = File.readlines(container_config).detect{|line|
262
+ line.include?('hwaddr')
263
+ }.to_s.split('=').last.to_s.downcase
264
+ if(File.exists?(container_config) && !hw.empty?)
265
+ running? # need to do a list!
266
+ ip = File.readlines('/proc/net/arp').detect{|line|
267
+ line.downcase.include?(hw)
268
+ }.to_s.split(' ').first.to_s.strip
269
+ if(ip.to_s.empty?)
270
+ nil
271
+ else
272
+ log.info "LXC Discovery: Found container address via HW addr: #{ip}"
273
+ ip
274
+ end
167
275
  end
168
276
  end
169
277
  end
@@ -177,8 +285,11 @@ class Lxc
177
285
  system("#{sudo}ln -s /proc/#{pid}/ns/net #{path}")
178
286
  res = %x{#{sudo}ip netns exec #{name} ip -4 addr show scope global | grep inet}
179
287
  system("#{sudo}rm -f #{path}")
180
- ip = res.strip.split(' ')[1].to_s.sub(%r{/.*$}, '').strip
181
- ip.empty? ? nil : ip
288
+ ips = res.split("\n").map do |line|
289
+ parts = line.split(' ')
290
+ {:address => parts[1].to_s.sub(%r{/.+$}, ''), :device => parts.last}
291
+ end
292
+ ips.empty? ? nil : ips
182
293
  end
183
294
  end
184
295
  end
@@ -189,23 +300,23 @@ class Lxc
189
300
 
190
301
  # Full path to container
191
302
  def container_path
192
- File.join(@base_path, name)
303
+ Pathname.new(@base_path).join(name)
193
304
  end
194
305
  alias_method :path, :container_path
195
306
 
196
307
  # Full path to container configuration file
197
308
  def container_config
198
- File.join(container_path, 'config')
309
+ container_path.join('config')
199
310
  end
200
311
  alias_method :config, :container_config
201
312
 
202
313
  def container_rootfs
203
- File.join(container_path, 'rootfs')
314
+ container_path.join('rootfs')
204
315
  end
205
316
  alias_method :rootfs, :container_rootfs
206
317
 
207
318
  def expand_path(path)
208
- File.join(container_rootfs, path)
319
+ container_rootfs.join(path)
209
320
  end
210
321
 
211
322
  def state
@@ -217,68 +328,82 @@ class Lxc
217
328
  end
218
329
 
219
330
  # Start the container
220
- def start
221
- run_command("#{sudo}lxc-start -n #{name} -d")
222
- run_command("#{sudo}lxc-wait -n #{name} -s RUNNING", :allow_failure_retry => 2)
331
+ def start(*args)
332
+ if(args.include?(:no_daemon))
333
+ run_command("#{sudo}lxc-start -n #{name}")
334
+ else
335
+ run_command("#{sudo}lxc-start -n #{name} -d")
336
+ wait_for_state(:running)
337
+ end
223
338
  end
224
339
 
225
340
  # Stop the container
226
341
  def stop
227
342
  run_command("#{sudo}lxc-stop -n #{name}", :allow_failure_retry => 3)
228
- run_command("#{sudo}lxc-wait -n #{name} -s STOPPED", :allow_failure_retry => 2)
343
+ wait_for_state(:stopped)
229
344
  end
230
345
 
231
346
  # Freeze the container
232
347
  def freeze
233
348
  run_command("#{sudo}lxc-freeze -n #{name}")
234
- run_command("#{sudo}lxc-wait -n #{name} -s FROZEN", :allow_failure_retry => 2)
349
+ wait_for_state(:frozen)
235
350
  end
236
351
 
237
352
  # Unfreeze the container
238
353
  def unfreeze
239
354
  run_command("#{sudo}lxc-unfreeze -n #{name}")
240
- run_command("#{sudo}lxc-wait -n #{name} -s RUNNING", :allow_failure_retry => 2)
355
+ wait_for_state(:running)
241
356
  end
242
357
 
243
358
  # Shutdown the container
244
359
  def shutdown
245
360
  run_command("#{sudo}lxc-shutdown -n #{name}")
246
- run_command("#{sudo}lxc-wait -n #{name} -s STOPPED", :allow_failure => true, :timeout => 10)
361
+ wait_for_state(:stopped, :timeout => 120)
362
+ # This block is for fedora/centos/anyone else that does not like lxc-shutdown
247
363
  if(running?)
248
364
  container_command('shutdown -h now')
249
- run_command("#{sudo}lxc-wait -n #{name} -s STOPPED")
365
+ wait_for_state(:stopped, :timeout => 120)
366
+ # If still running here, something is wrong
367
+ if(running?)
368
+ raise "Failed to shutdown container: #{name}"
369
+ end
250
370
  end
251
371
  end
252
372
 
253
- def knife_container(cmd, ip)
254
- require 'chef/knife/ssh'
255
- Chef::Knife::Ssh.load_deps
256
- k = Chef::Knife::Ssh.new([
257
- ip, '-m', '-i', '/opt/hw-lxc-config/id_rsa', '--no-host-key-verify', cmd
258
- ])
259
- e = nil
373
+ def direct_container_command(command, args={})
374
+ com = "#{sudo}ssh root@#{args[:ip] || container_ip} -i /opt/hw-lxc-config/id_rsa -oStrictHostKeyChecking=no '#{command}'"
260
375
  begin
261
- e = k.run
262
- rescue SystemExit => e
376
+ cmd = Mixlib::ShellOut.new(com,
377
+ :live_stream => args[:live_stream],
378
+ :timeout => args[:timeout] || 1200
379
+ )
380
+ cmd.run_command
381
+ cmd.error!
382
+ true
383
+ rescue
384
+ raise if args[:raise_on_failure]
385
+ false
263
386
  end
264
- raise CommandFailed.new(cmd) if e.nil? || e != 0
265
387
  end
388
+ alias_method :knife_container, :direct_container_command
266
389
 
267
390
  # Simple helper to shell out
268
391
  def run_command(cmd, args={})
269
392
  retries = args[:allow_failure_retry].to_i
270
393
  begin
271
394
  shlout = Mixlib::ShellOut.new(cmd,
272
- :logger => Chef::Log.logger,
273
- :live_stream => STDOUT,
274
- :timeout => args[:timeout] || 1200
395
+ :logger => defined?(Chef::Log) ? Chef::Log.logger : log,
396
+ :live_stream => args[:livestream] ? nil : STDOUT,
397
+ :timeout => args[:timeout] || 1200,
398
+ :environment => {'HOME' => detect_home}
275
399
  )
276
400
  shlout.run_command
277
401
  shlout.error!
402
+ shlout
278
403
  rescue Mixlib::ShellOut::ShellCommandFailed, CommandFailed, Mixlib::ShellOut::CommandTimeout
279
404
  if(retries > 0)
280
- Chef::Log.warn "LXC run command failed: #{cmd}"
281
- Chef::Log.warn "Retrying command. #{args[:allow_failure_retry].to_i - retries} of #{args[:allow_failure_retry].to_i} retries remain"
405
+ log.warn "LXC run command failed: #{cmd}"
406
+ log.warn "Retrying command. #{args[:allow_failure_retry].to_i - retries} of #{args[:allow_failure_retry].to_i} retries remain"
282
407
  sleep(0.3)
283
408
  retries -= 1
284
409
  retry
@@ -290,16 +415,44 @@ class Lxc
290
415
  end
291
416
  end
292
417
 
418
+ def wait_for_state(desired_state, args={})
419
+ args[:sleep_interval] ||= 1.0
420
+ wait_total = 0.0
421
+ until(state == desired_state.to_sym || (args[:timeout].to_i > 0 && wait_total.to_i > args[:timeout].to_i))
422
+ sleep(args[:sleep_interval])
423
+ wait_total += args[:sleep_interval]
424
+ end
425
+ end
426
+
427
+ # Detect HOME environment variable. If not an acceptable
428
+ # value, set to /root or /tmp
429
+ def detect_home(set_if_missing=false)
430
+ if(ENV['HOME'] && Pathname.new(ENV['HOME']).absolute?)
431
+ ENV['HOME']
432
+ else
433
+ home = File.directory?('/root') && File.writable?('/root') ? '/root' : '/tmp'
434
+ if(set_if_missing)
435
+ ENV['HOME'] = home
436
+ end
437
+ home
438
+ end
439
+ end
440
+
293
441
  # cmd:: Shell command string
294
442
  # retries:: Number of retry attempts (1 second sleep interval)
295
443
  # Runs command in container via ssh
296
444
  def container_command(cmd, retries=1)
297
445
  begin
298
- knife_container(cmd, container_ip(5))
446
+ detect_home(true)
447
+ direct_container_command(cmd,
448
+ :ip => container_ip(5),
449
+ :live_stream => STDOUT,
450
+ :raise_on_failure => true
451
+ )
299
452
  rescue => e
300
453
  if(retries.to_i > 0)
301
- Chef::Log.info "Encountered error running container command (#{cmd}): #{e}"
302
- Chef::Log.info "Retrying command..."
454
+ log.info "Encountered error running container command (#{cmd}): #{e}"
455
+ log.info "Retrying command..."
303
456
  retries = retries.to_i - 1
304
457
  sleep(1)
305
458
  retry
@@ -309,4 +462,16 @@ class Lxc
309
462
  end
310
463
  end
311
464
 
465
+ def log
466
+ if(defined?(Chef::Log))
467
+ Chef::Log
468
+ else
469
+ unless(@logger)
470
+ require 'logger'
471
+ @logger = Logger.new('/dev/null')
472
+ end
473
+ @logger
474
+ end
475
+ end
476
+
312
477
  end
@@ -7,6 +7,9 @@ class LxcFileConfig
7
7
  def generate_config(resource)
8
8
  config = []
9
9
  config << "lxc.utsname = #{resource.utsname}"
10
+ if(resource.aa_profile)
11
+ config << "lxc.aa_profile = #{resource.aa_profile}"
12
+ end
10
13
  [resource.network].flatten.each do |net_hash|
11
14
  nhsh = Mash.new(net_hash)
12
15
  flags = nhsh.delete(:flags)
@@ -0,0 +1,51 @@
1
+ unless(defined?(LxcMonkey))
2
+ require 'chef/resource/execute'
3
+ require 'chef/provider/execute'
4
+
5
+ module LxcMonkey
6
+ module Provider
7
+ class << self
8
+ def included(klass)
9
+ klass.class_eval do
10
+ alias_method :non_monkey_shell_out!, :shell_out!
11
+ alias_method :shell_out!, :monkey_shell_out!
12
+ end
13
+ end
14
+ end
15
+
16
+ def monkey_shell_out!(com, opts)
17
+ if(str = @new_resource.stream_output)
18
+ opts[:live_stream] = str.kind_of?(IO) ? str : STDOUT
19
+ end
20
+ non_monkey_shell_out!(com, opts)
21
+ end
22
+ end
23
+ module Resource
24
+
25
+ class << self
26
+ def included(klass)
27
+ klass.class_eval do
28
+ alias_method :non_monkey_initialize, :initialize
29
+ alias_method :initialize, :monkey_initialize
30
+ end
31
+ end
32
+ end
33
+
34
+ def monkey_initialize(*args)
35
+ non_monkey_initialize(*args)
36
+ @stream_output = nil
37
+ end
38
+
39
+ def stream_output(arg=nil)
40
+ set_or_return(
41
+ :stream_output,
42
+ arg,
43
+ :kind_of => [TrueClass,FalseClass,IO]
44
+ )
45
+ end
46
+ end
47
+ end
48
+
49
+ Chef::Resource::Execute.send(:include, LxcMonkey::Resource)
50
+ Chef::Provider::Execute.send(:include, LxcMonkey::Provider)
51
+ end