elecksee 1.0.2 → 1.0.4

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