elecksee 1.0.2 → 1.0.4

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 (49) hide show
  1. data/CHANGELOG.md +4 -0
  2. data/bin/lxc-awesome-ephemeral +57 -2
  3. data/lib/elecksee/clone.rb +15 -0
  4. data/lib/elecksee/ephemeral.rb +310 -0
  5. data/lib/elecksee/helpers.rb +70 -0
  6. data/lib/elecksee/lxc.rb +409 -5
  7. data/lib/elecksee/lxc_file_config.rb +86 -0
  8. data/lib/elecksee/storage/overlay_directory.rb +31 -0
  9. data/lib/elecksee/storage/overlay_mount.rb +60 -0
  10. data/lib/elecksee/storage/virtual_device.rb +81 -0
  11. data/lib/elecksee/version.rb +1 -1
  12. metadata +9 -39
  13. data/Gemfile.lock +0 -18
  14. data/lib/elecksee/awesome.rb +0 -14
  15. data/lib/elecksee/vendor/lxc/CHANGELOG.md +0 -37
  16. data/lib/elecksee/vendor/lxc/Gemfile +0 -4
  17. data/lib/elecksee/vendor/lxc/Gemfile.lock +0 -41
  18. data/lib/elecksee/vendor/lxc/README.md +0 -112
  19. data/lib/elecksee/vendor/lxc/attributes/default.rb +0 -28
  20. data/lib/elecksee/vendor/lxc/files/default/knife_lxc +0 -228
  21. data/lib/elecksee/vendor/lxc/files/default/lxc-awesome-ephemeral +0 -495
  22. data/lib/elecksee/vendor/lxc/libraries/lxc.rb +0 -366
  23. data/lib/elecksee/vendor/lxc/libraries/lxc_expanded_resources.rb +0 -40
  24. data/lib/elecksee/vendor/lxc/libraries/lxc_file_config.rb +0 -84
  25. data/lib/elecksee/vendor/lxc/libraries/monkey.rb +0 -51
  26. data/lib/elecksee/vendor/lxc/metadata.rb +0 -12
  27. data/lib/elecksee/vendor/lxc/providers/config.rb +0 -75
  28. data/lib/elecksee/vendor/lxc/providers/container.rb +0 -318
  29. data/lib/elecksee/vendor/lxc/providers/default.rb +0 -57
  30. data/lib/elecksee/vendor/lxc/providers/ephemeral.rb +0 -40
  31. data/lib/elecksee/vendor/lxc/providers/fstab.rb +0 -30
  32. data/lib/elecksee/vendor/lxc/providers/interface.rb +0 -45
  33. data/lib/elecksee/vendor/lxc/providers/service.rb +0 -53
  34. data/lib/elecksee/vendor/lxc/recipes/containers.rb +0 -13
  35. data/lib/elecksee/vendor/lxc/recipes/default.rb +0 -58
  36. data/lib/elecksee/vendor/lxc/recipes/install_dependencies.rb +0 -15
  37. data/lib/elecksee/vendor/lxc/recipes/knife.rb +0 -37
  38. data/lib/elecksee/vendor/lxc/resources/config.rb +0 -19
  39. data/lib/elecksee/vendor/lxc/resources/container.rb +0 -54
  40. data/lib/elecksee/vendor/lxc/resources/default.rb +0 -12
  41. data/lib/elecksee/vendor/lxc/resources/ephemeral.rb +0 -13
  42. data/lib/elecksee/vendor/lxc/resources/fstab.rb +0 -12
  43. data/lib/elecksee/vendor/lxc/resources/interface.rb +0 -13
  44. data/lib/elecksee/vendor/lxc/resources/service.rb +0 -5
  45. data/lib/elecksee/vendor/lxc/templates/default/client.rb.erb +0 -13
  46. data/lib/elecksee/vendor/lxc/templates/default/default-lxc.erb +0 -3
  47. data/lib/elecksee/vendor/lxc/templates/default/file_content.erb +0 -2
  48. data/lib/elecksee/vendor/lxc/templates/default/fstab.erb +0 -5
  49. data/lib/elecksee/vendor/lxc/templates/default/interface.erb +0 -27
data/lib/elecksee/lxc.rb CHANGED
@@ -1,7 +1,411 @@
1
+ require 'elecksee/helpers'
1
2
  require 'mixlib/shellout'
3
+ require 'pathname'
4
+ require 'tmpdir'
2
5
 
3
- require File.expand_path(
4
- File.join(
5
- File.dirname(__FILE__), 'vendor/lxc/libraries/lxc.rb'
6
- )
7
- )
6
+ class Lxc
7
+
8
+ # Pathname#join does not act like File#join when joining paths that
9
+ # begin with '/', and that's dumb. So we'll make our own Pathname,
10
+ # with a #join that uses File
11
+ class Pathname < ::Pathname
12
+ def join(*args)
13
+ self.class.new(::File.join(self.to_path, *args))
14
+ end
15
+ end
16
+
17
+ include Helpers
18
+
19
+ attr_reader :name, :base_path, :lease_file, :preferred_device
20
+
21
+ class << self
22
+
23
+ include Helpers
24
+
25
+ attr_accessor :use_sudo
26
+ attr_accessor :base_path
27
+
28
+ def sudo
29
+ case use_sudo
30
+ when TrueClass
31
+ 'sudo '
32
+ when String
33
+ "#{use_sudo} "
34
+ end
35
+ end
36
+
37
+ def base_path
38
+ @base_path || '/var/lib/lxc'
39
+ end
40
+
41
+ # List running containers
42
+ def running
43
+ full_list[:running]
44
+ end
45
+
46
+ # List stopped containers
47
+ def stopped
48
+ full_list[:stopped]
49
+ end
50
+
51
+ # List frozen containers
52
+ def frozen
53
+ full_list[:frozen]
54
+ end
55
+
56
+ # name:: name of container
57
+ # Returns if container exists
58
+ def exists?(name)
59
+ list.include?(name)
60
+ end
61
+
62
+ # List of containers
63
+ def list
64
+ Dir.glob(File.join(base_path, '*')).map do |item|
65
+ if(File.directory?(item) && File.exists?(File.join(item, 'config')))
66
+ File.basename(item)
67
+ end
68
+ end.compact
69
+ end
70
+
71
+ # name:: Name of container
72
+ # Returns information about given container
73
+ def info(name)
74
+ res = {:state => nil, :pid => nil}
75
+ info = run_command("#{sudo}lxc-info -n #{name}").stdout.split("\n")
76
+ if(info.first)
77
+ parts = info.first.split(' ')
78
+ res[:state] = parts.last.downcase.to_sym
79
+ parts = info.last.split(' ')
80
+ res[:pid] = parts.last.to_i
81
+ res
82
+ else
83
+ res[:state] = :unknown
84
+ res[:pid] = -1
85
+ end
86
+ end
87
+
88
+ # Return full container information list
89
+ def full_list
90
+ res = {}
91
+ list.each do |item|
92
+ item_info = info(item)
93
+ res[item_info[:state]] ||= []
94
+ res[item_info[:state]] << item
95
+ end
96
+ res
97
+ end
98
+
99
+ # ip:: IP address
100
+ # Returns if IP address is alive
101
+ def connection_alive?(ip)
102
+ %x{ping -c 1 -W 1 #{ip}}
103
+ $?.exitstatus == 0
104
+ end
105
+ end
106
+
107
+ # name:: name of container
108
+ # args:: Argument hash
109
+ # - :base_path -> path to container directory
110
+ # - :dnsmasq_lease_file -> path to lease file
111
+ # - :net_device -> network device to use within container for ssh connection
112
+ def initialize(name, args={})
113
+ @name = name
114
+ @base_path = args[:base_path] || self.class.base_path
115
+ @lease_file = args[:dnsmasq_lease_file] || '/var/lib/misc/dnsmasq.leases'
116
+ @preferred_device = args[:net_device]
117
+ end
118
+
119
+ # Returns if container exists
120
+ def exists?
121
+ self.class.exists?(name)
122
+ end
123
+
124
+ # Returns if container is running
125
+ def running?
126
+ self.class.info(name)[:state] == :running
127
+ end
128
+
129
+ # Returns if container is stopped
130
+ def stopped?
131
+ self.class.info(name)[:state] == :stopped
132
+ end
133
+
134
+ # Returns if container is frozen
135
+ def frozen?
136
+ self.class.info(name)[:state] == :frozen
137
+ end
138
+
139
+ # retries:: Number of discovery attempt (3 second sleep intervals)
140
+ # Returns container IP
141
+ def container_ip(retries=0, raise_on_fail=false)
142
+ (retries.to_i + 1).times do
143
+ ip = proc_detected_address || hw_detected_address || leased_address || lxc_stored_address
144
+ if(ip.is_a?(Array))
145
+ # Filter any found loopbacks
146
+ ip.delete_if{|info| info[:device].start_with?('lo') }
147
+ ip = ip.detect do |info|
148
+ if(@preferred_device)
149
+ info[:device] == @preferred_device
150
+ else
151
+ true
152
+ end
153
+ end
154
+ ip = ip[:address] if ip
155
+ end
156
+ return ip if ip && self.class.connection_alive?(ip)
157
+ log.warn "LXC IP discovery: Failed to detect live IP"
158
+ sleep(3) if retries > 0
159
+ end
160
+ raise "Failed to detect live IP address for container: #{name}" if raise_on_fail
161
+ end
162
+
163
+ # Container address via lxc config file
164
+ def lxc_stored_address
165
+ if(File.exists?(container_config))
166
+ ip = File.readlines(container_config).detect{|line|
167
+ line.include?('ipv4')
168
+ }.to_s.split('=').last.to_s.strip
169
+ if(ip.to_s.empty?)
170
+ nil
171
+ else
172
+ log.info "LXC Discovery: Found container address via storage: #{ip}"
173
+ ip
174
+ end
175
+ end
176
+ end
177
+
178
+ # Container address via dnsmasq lease
179
+ def leased_address
180
+ ip = nil
181
+ if(File.exists?(@lease_file))
182
+ leases = File.readlines(@lease_file).map{|line| line.split(' ')}
183
+ leases.each do |lease|
184
+ if(lease.include?(name))
185
+ ip = lease[2]
186
+ end
187
+ end
188
+ end
189
+ if(ip.to_s.empty?)
190
+ nil
191
+ else
192
+ log.info "LXC Discovery: Found container address via DHCP lease: #{ip}"
193
+ ip
194
+ end
195
+ end
196
+
197
+ def hw_detected_address
198
+ if(container_config.readable?)
199
+ hw = File.readlines(container_config).detect{|line|
200
+ line.include?('hwaddr')
201
+ }.to_s.split('=').last.to_s.downcase
202
+ if(File.exists?(container_config) && !hw.empty?)
203
+ running? # need to do a list!
204
+ ip = File.readlines('/proc/net/arp').detect{|line|
205
+ line.downcase.include?(hw)
206
+ }.to_s.split(' ').first.to_s.strip
207
+ if(ip.to_s.empty?)
208
+ nil
209
+ else
210
+ log.info "LXC Discovery: Found container address via HW addr: #{ip}"
211
+ ip
212
+ end
213
+ end
214
+ end
215
+ end
216
+
217
+ def proc_detected_address(base='/run/netns')
218
+ if(pid != -1)
219
+ Dir.mktmpdir do |t_dir|
220
+ name = File.basename(t_dir)
221
+ path = File.join(base, name)
222
+ system("#{sudo}mkdir -p #{base}")
223
+ system("#{sudo}ln -s /proc/#{pid}/ns/net #{path}")
224
+ res = %x{#{sudo}ip netns exec #{name} ip -4 addr show scope global | grep inet}
225
+ system("#{sudo}rm -f #{path}")
226
+ ips = res.split("\n").map do |line|
227
+ parts = line.split(' ')
228
+ {:address => parts[1].to_s.sub(%r{/.+$}, ''), :device => parts.last}
229
+ end
230
+ ips.empty? ? nil : ips
231
+ end
232
+ end
233
+ end
234
+
235
+ # Full path to container
236
+ def container_path
237
+ Pathname.new(@base_path).join(name)
238
+ end
239
+ alias_method :path, :container_path
240
+
241
+ # Full path to container configuration file
242
+ def container_config
243
+ container_path.join('config')
244
+ end
245
+ alias_method :config, :container_config
246
+
247
+ def container_rootfs
248
+ container_path.join('rootfs')
249
+ end
250
+ alias_method :rootfs, :container_rootfs
251
+
252
+ def expand_path(path)
253
+ container_rootfs.join(path)
254
+ end
255
+
256
+ def state
257
+ self.class.info(name)[:state]
258
+ end
259
+
260
+ def pid
261
+ self.class.info(name)[:pid]
262
+ end
263
+
264
+ # Start the container
265
+ def start(*args)
266
+ if(args.include?(:no_daemon))
267
+ run_command("#{sudo}lxc-start -n #{name}")
268
+ else
269
+ run_command("#{sudo}lxc-start -n #{name} -d")
270
+ wait_for_state(:running)
271
+ end
272
+ end
273
+
274
+ # Stop the container
275
+ def stop
276
+ run_command("#{sudo}lxc-stop -n #{name}", :allow_failure_retry => 3)
277
+ wait_for_state(:stopped)
278
+ end
279
+
280
+ # Freeze the container
281
+ def freeze
282
+ run_command("#{sudo}lxc-freeze -n #{name}")
283
+ wait_for_state(:frozen)
284
+ end
285
+
286
+ # Unfreeze the container
287
+ def unfreeze
288
+ run_command("#{sudo}lxc-unfreeze -n #{name}")
289
+ wait_for_state(:running)
290
+ end
291
+
292
+ # Shutdown the container
293
+ def shutdown
294
+ run_command("#{sudo}lxc-shutdown -n #{name}")
295
+ wait_for_state(:stopped, :timeout => 120)
296
+ # This block is for fedora/centos/anyone else that does not like lxc-shutdown
297
+ if(running?)
298
+ container_command('shutdown -h now')
299
+ wait_for_state(:stopped, :timeout => 120)
300
+ # If still running here, something is wrong
301
+ if(running?)
302
+ raise "Failed to shutdown container: #{name}"
303
+ end
304
+ end
305
+ end
306
+
307
+ def direct_container_command(command, args={})
308
+ com = "#{sudo}ssh root@#{args[:ip] || container_ip} -i /opt/hw-lxc-config/id_rsa -oStrictHostKeyChecking=no '#{command}'"
309
+ begin
310
+ cmd = Mixlib::ShellOut.new(com,
311
+ :live_stream => args[:live_stream],
312
+ :timeout => args[:timeout] || 1200
313
+ )
314
+ cmd.run_command
315
+ cmd.error!
316
+ true
317
+ rescue
318
+ raise if args[:raise_on_failure]
319
+ false
320
+ end
321
+ end
322
+ alias_method :knife_container, :direct_container_command
323
+
324
+ # Simple helper to shell out
325
+ def run_command(cmd, args={})
326
+ retries = args[:allow_failure_retry].to_i
327
+ begin
328
+ shlout = Mixlib::ShellOut.new(cmd,
329
+ :logger => defined?(Chef) ? Chef::Log.logger : log,
330
+ :live_stream => args[:livestream] ? nil : STDOUT,
331
+ :timeout => args[:timeout] || 1200,
332
+ :environment => {'HOME' => detect_home}
333
+ )
334
+ shlout.run_command
335
+ shlout.error!
336
+ shlout
337
+ rescue Mixlib::ShellOut::ShellCommandFailed, CommandFailed, Mixlib::ShellOut::CommandTimeout
338
+ if(retries > 0)
339
+ log.warn "LXC run command failed: #{cmd}"
340
+ log.warn "Retrying command. #{args[:allow_failure_retry].to_i - retries} of #{args[:allow_failure_retry].to_i} retries remain"
341
+ sleep(0.3)
342
+ retries -= 1
343
+ retry
344
+ elsif(args[:allow_failure])
345
+ true
346
+ else
347
+ raise
348
+ end
349
+ end
350
+ end
351
+
352
+ def wait_for_state(desired_state, args={})
353
+ args[:sleep_interval] ||= 1.0
354
+ wait_total = 0.0
355
+ until(state == desired_state.to_sym || (args[:timeout].to_i > 0 && wait_total.to_i > args[:timeout].to_i))
356
+ sleep(args[:sleep_interval])
357
+ wait_total += args[:sleep_interval]
358
+ end
359
+ end
360
+
361
+ # Detect HOME environment variable. If not an acceptable
362
+ # value, set to /root or /tmp
363
+ def detect_home(set_if_missing=false)
364
+ if(ENV['HOME'] && Pathname.new(ENV['HOME']).absolute?)
365
+ ENV['HOME']
366
+ else
367
+ home = File.directory?('/root') && File.writable?('/root') ? '/root' : '/tmp'
368
+ if(set_if_missing)
369
+ ENV['HOME'] = home
370
+ end
371
+ home
372
+ end
373
+ end
374
+
375
+ # cmd:: Shell command string
376
+ # retries:: Number of retry attempts (1 second sleep interval)
377
+ # Runs command in container via ssh
378
+ def container_command(cmd, retries=1)
379
+ begin
380
+ detect_home(true)
381
+ direct_container_command(cmd,
382
+ :ip => container_ip(5),
383
+ :live_stream => STDOUT,
384
+ :raise_on_failure => true
385
+ )
386
+ rescue => e
387
+ if(retries.to_i > 0)
388
+ log.info "Encountered error running container command (#{cmd}): #{e}"
389
+ log.info "Retrying command..."
390
+ retries = retries.to_i - 1
391
+ sleep(1)
392
+ retry
393
+ else
394
+ raise e
395
+ end
396
+ end
397
+ end
398
+
399
+ def log
400
+ if(defined?(Chef))
401
+ Chef::Log
402
+ else
403
+ unless(@logger)
404
+ require 'logger'
405
+ @logger = Logger.new('/dev/null')
406
+ end
407
+ @logger
408
+ end
409
+ end
410
+
411
+ end
@@ -0,0 +1,86 @@
1
+ class Lxc
2
+ class FileConfig
3
+
4
+ attr_reader :network
5
+ attr_reader :base
6
+
7
+ class << self
8
+ def generate_config(resource)
9
+ config = []
10
+ config << "lxc.utsname = #{resource.utsname}"
11
+ if(resource.aa_profile)
12
+ config << "lxc.aa_profile = #{resource.aa_profile}"
13
+ end
14
+ [resource.network].flatten.each do |net_hash|
15
+ nhsh = Mash.new(net_hash)
16
+ flags = nhsh.delete(:flags)
17
+ %w(type link).each do |k|
18
+ config << "lxc.network.#{k} = #{nhsh.delete(k)}" if nhsh[k]
19
+ end
20
+ nhsh.each_pair do |k,v|
21
+ config << "lxc.network.#{k} = #{v}"
22
+ end
23
+ if(flags)
24
+ config << "lxc.network.flags = #{flags}"
25
+ end
26
+ end
27
+ if(resource.cap_drop)
28
+ config << "lxc.cap.drop = #{Array(resource.cap_drop).join(' ')}"
29
+ end
30
+ %w(pts tty arch devttydir mount mount_entry rootfs rootfs_mount pivotdir).each do |k|
31
+ config << "lxc.#{k.sub('_', '.')} = #{resource.send(k)}" if resource.send(k)
32
+ end
33
+ prefix = 'lxc.cgroup'
34
+ resource.cgroup.each_pair do |key, value|
35
+ if(value.is_a?(Array))
36
+ value.each do |val|
37
+ config << "#{prefix}.#{key} = #{val}"
38
+ end
39
+ else
40
+ config << "#{prefix}.#{key} = #{value}"
41
+ end
42
+ end
43
+ config.join("\n") + "\n"
44
+ end
45
+
46
+ end
47
+
48
+ def initialize(path)
49
+ raise 'LXC config file not found' unless File.exists?(path)
50
+ @path = path
51
+ @network = []
52
+ @base = Mash.new
53
+ parse!
54
+ end
55
+
56
+ private
57
+
58
+ def parse!
59
+ cur_net = nil
60
+ File.readlines(@path).each do |line|
61
+ if(line.start_with?('lxc.network'))
62
+ parts = line.split('=')
63
+ name = parts.first.split('.').last.strip
64
+ if(name.to_sym == :type)
65
+ @network << cur_net if cur_net
66
+ cur_net = Mash.new
67
+ end
68
+ if(cur_net)
69
+ cur_net[name] = parts.last.strip
70
+ else
71
+ raise "Expecting 'lxc.network.type' to start network config block. Found: 'lxc.network.#{name}'"
72
+ end
73
+ else
74
+ parts = line.split('=')
75
+ name = parts.first.sub('lxc.', '').strip
76
+ if(@base[name])
77
+ @base[name] = [@base[name], parts.last.strip].flatten
78
+ else
79
+ @base[name] = parts.last
80
+ end
81
+ end
82
+ end
83
+ @network << cur_net if cur_net
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,31 @@
1
+ require 'elecksee/helpers'
2
+
3
+ class Lxc
4
+ class OverlayDirectory
5
+
6
+ attr_reader :name
7
+ attr_reader :tmp_dir
8
+
9
+ def initialize(name, args={})
10
+ @name = name
11
+ @tmp_dir = args[:tmp_dir] || '/tmp/lxc/ephemerals'
12
+ create
13
+ end
14
+
15
+ def overlay_path
16
+ File.join(tmp_dir, 'virt-overlays', name)
17
+ end
18
+ alias_method :target_path, :overlay_path
19
+
20
+ def create
21
+ unless(File.directory?(overlay_path))
22
+ FileUtils.mkdir_p(overlay_path)
23
+ end
24
+ end
25
+
26
+ def destroy
27
+ FileUtils.rm_rf(overlay_path) if File.directory?(overlay_path)
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,60 @@
1
+ require 'elecksee/helpers'
2
+
3
+ class Lxc
4
+ class OverlayMount
5
+
6
+ include Helpers
7
+
8
+ attr_reader :base
9
+ attr_reader :overlay
10
+ attr_reader :target
11
+ attr_reader :overlay_type
12
+
13
+ def initialize(args={})
14
+ validate!(args)
15
+ @base = args[:base]
16
+ @overlay = args[:overlay]
17
+ @target = args[:target]
18
+ @overlay_type = args[:overlay_type] || 'overlayfs'
19
+ end
20
+
21
+ def mount
22
+ unless(mounted?)
23
+ case overlay_type
24
+ when 'aufs'
25
+ cmd = "mount -t aufs -o br=#{overlay}=rw:#{base}=ro,noplink none #{target}"
26
+ when 'overlayfs'
27
+ cmd = "mount -t overlayfs -oupperdir=#{overlay},lowerdir=#{base} none #{target}"
28
+ else
29
+ raise "Invalid overlay type provided: #{overlay_type}"
30
+ end
31
+ command(cmd, :sudo => true)
32
+ true
33
+ end
34
+ end
35
+
36
+ def mounted?
37
+ command("mount").stdout.include?(target)
38
+ end
39
+
40
+ def unmount
41
+ if(mounted?)
42
+ command("umount #{target}", :sudo => true, :allow_failure => true)
43
+ true
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def validate!(args)
50
+ [:base, :overlay, :target].each do |required|
51
+ unless(args[required])
52
+ raise ArgumentError.new "Missing required argument: #{required}"
53
+ end
54
+ unless(File.directory?(args[required]))
55
+ raise TypeError.new "Provided argument is not a valid directory for #{required}: #{args[required]}"
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,81 @@
1
+ require 'elecksee/helpers'
2
+
3
+ class Lxc
4
+
5
+ class VirtualDevice
6
+
7
+ include Helpers
8
+
9
+ attr_reader :name
10
+ attr_reader :tmp_dir
11
+ attr_reader :size
12
+ attr_reader :tmp_fs
13
+ attr_reader :fs_type
14
+
15
+ def initialize(name, args={})
16
+ @name = name
17
+ @tmp_dir = args[:tmp_dir] || '/tmp/lxc/ephemerals'
18
+ @size = args[:size] || 2000
19
+ @fs_type = args[:fs_type] || 'ext4'
20
+ @tmp_fs = !!args[:tmp_fs]
21
+ @fs_type = 'tmpfs' if @tmp_fs
22
+ create
23
+ end
24
+
25
+ def device_path
26
+ tmp_fs ? 'none' : File.join(tmp_dir, 'virt-imgs', name)
27
+ end
28
+
29
+ def mount_path
30
+ File.join(tmp_dir, 'virt-mnts', name)
31
+ end
32
+ alias_method :target_path, :mount_path
33
+
34
+ def create
35
+ make_directories!
36
+ unless(tmp_fs)
37
+ command("dd if=/dev/zero of=#{@device_path} bs=1k seek=#{sive}k count=1 > /dev/null")
38
+ command("echo \"y\" | mkfs -t #{fs_type} #{size} > /dev/null")
39
+ end
40
+ end
41
+
42
+ def mounted?
43
+ command("mount").stdout.include?(mount_path)
44
+ end
45
+
46
+ def mount
47
+ unless(mounted?)
48
+ command("mount -t #{fs_type}#{mount_options} #{device_path} #{mount_path}", :sudo => true)
49
+ true
50
+ end
51
+ end
52
+
53
+ def unmount
54
+ if(mounted?)
55
+ command("umount #{mount_path}", :sudo => true)
56
+ true
57
+ end
58
+ end
59
+
60
+ def destroy
61
+ unmount
62
+ File.delete(device_path) if File.file?(device_path)
63
+ FileUtils.rm_rf(device_path) if File.directory?(device_path)
64
+ FileUtils.rmdir(mount_path) if File.directory?(mount_path)
65
+ end
66
+
67
+ private
68
+
69
+ def mount_options
70
+ ' -o loop' unless tmp_fs
71
+ end
72
+
73
+ def make_directories!
74
+ [device_path, mount_path].each do |path|
75
+ unless(File.directory?(path))
76
+ FileUtils.mkdir_p(path)
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -2,5 +2,5 @@ module Elecksee
2
2
  class Version < Gem::Version
3
3
  end
4
4
 
5
- VERSION = Version.new('1.0.2')
5
+ VERSION = Version.new('1.0.4')
6
6
  end