vagabond 0.2.0 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
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