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
@@ -1,366 +0,0 @@
1
- require 'pathname'
2
- require 'tmpdir'
3
-
4
- class Lxc
5
- class CommandFailed < StandardError
6
- end
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
- attr_reader :name
18
-
19
- class << self
20
-
21
- attr_accessor :use_sudo
22
-
23
- def sudo
24
- case use_sudo
25
- when TrueClass
26
- 'sudo '
27
- when String
28
- "#{use_sudo} "
29
- end
30
- end
31
-
32
- # List running containers
33
- def running
34
- full_list[:running]
35
- end
36
-
37
- # List stopped containers
38
- def stopped
39
- full_list[:stopped]
40
- end
41
-
42
- # List frozen containers
43
- def frozen
44
- full_list[:frozen]
45
- end
46
-
47
- # name:: name of container
48
- # Returns if container exists
49
- def exists?(name)
50
- list.include?(name)
51
- end
52
-
53
- # List of containers
54
- def list
55
- %x{#{sudo}lxc-ls}.split("\n").uniq
56
- end
57
-
58
- # name:: Name of container
59
- # Returns information about given container
60
- def info(name)
61
- res = {:state => nil, :pid => nil}
62
- info = %x{#{sudo}lxc-info -n #{name}}.split("\n")
63
- parts = info.first.split(' ')
64
- res[:state] = parts.last.downcase.to_sym
65
- parts = info.last.split(' ')
66
- res[:pid] = parts.last.to_i
67
- res
68
- end
69
-
70
- # Return full container information list
71
- def full_list
72
- res = {}
73
- list.each do |item|
74
- item_info = info(item)
75
- res[item_info[:state]] ||= []
76
- res[item_info[:state]] << item
77
- end
78
- res
79
- end
80
-
81
- # ip:: IP address
82
- # Returns if IP address is alive
83
- def connection_alive?(ip)
84
- %x{ping -c 1 -W 1 #{ip}}
85
- $?.exitstatus == 0
86
- end
87
- end
88
-
89
- # name:: name of container
90
- # args:: Argument hash
91
- # - :base_path -> path to container directory
92
- # - :dnsmasq_lease_file -> path to lease file
93
- def initialize(name, args={})
94
- @name = name
95
- @base_path = args[:base_path] || '/var/lib/lxc'
96
- @lease_file = args[:dnsmasq_lease_file] || '/var/lib/misc/dnsmasq.leases'
97
- end
98
-
99
- # Returns if container exists
100
- def exists?
101
- self.class.exists?(name)
102
- end
103
-
104
- # Returns if container is running
105
- def running?
106
- self.class.info(name)[:state] == :running
107
- end
108
-
109
- # Returns if container is stopped
110
- def stopped?
111
- self.class.info(name)[:state] == :stopped
112
- end
113
-
114
- # Returns if container is frozen
115
- def frozen?
116
- self.class.info(name)[:state] == :frozen
117
- end
118
-
119
- # retries:: Number of discovery attempt (3 second sleep intervals)
120
- # Returns container IP
121
- def container_ip(retries=0, raise_on_fail=false)
122
- (retries.to_i + 1).times do
123
- ip = proc_detected_address || hw_detected_address || leased_address || lxc_stored_address
124
- return ip if ip && self.class.connection_alive?(ip)
125
- log.warn "LXC IP discovery: Failed to detect live IP"
126
- sleep(3) if retries > 0
127
- end
128
- raise "Failed to detect live IP address for container: #{name}" if raise_on_fail
129
- end
130
-
131
- # Container address via lxc config file
132
- def lxc_stored_address
133
- if(File.exists?(container_config))
134
- ip = File.readlines(container_config).detect{|line|
135
- line.include?('ipv4')
136
- }.to_s.split('=').last.to_s.strip
137
- if(ip.to_s.empty?)
138
- nil
139
- else
140
- log.info "LXC Discovery: Found container address via storage: #{ip}"
141
- ip
142
- end
143
- end
144
- end
145
-
146
- # Container address via dnsmasq lease
147
- def leased_address
148
- ip = nil
149
- if(File.exists?(@lease_file))
150
- leases = File.readlines(@lease_file).map{|line| line.split(' ')}
151
- leases.each do |lease|
152
- if(lease.include?(name))
153
- ip = lease[2]
154
- end
155
- end
156
- end
157
- if(ip.to_s.empty?)
158
- nil
159
- else
160
- log.info "LXC Discovery: Found container address via DHCP lease: #{ip}"
161
- ip
162
- end
163
- end
164
-
165
- def hw_detected_address
166
- if(container_config.readable?)
167
- hw = File.readlines(container_config).detect{|line|
168
- line.include?('hwaddr')
169
- }.to_s.split('=').last.to_s.downcase
170
- if(File.exists?(container_config) && !hw.empty?)
171
- running? # need to do a list!
172
- ip = File.readlines('/proc/net/arp').detect{|line|
173
- line.downcase.include?(hw)
174
- }.to_s.split(' ').first.to_s.strip
175
- if(ip.to_s.empty?)
176
- nil
177
- else
178
- log.info "LXC Discovery: Found container address via HW addr: #{ip}"
179
- ip
180
- end
181
- end
182
- end
183
- end
184
-
185
- def proc_detected_address(base='/run/netns')
186
- if(pid != -1)
187
- Dir.mktmpdir do |t_dir|
188
- name = File.basename(t_dir)
189
- path = File.join(base, name)
190
- system("#{sudo}mkdir -p #{base}")
191
- system("#{sudo}ln -s /proc/#{pid}/ns/net #{path}")
192
- res = %x{#{sudo}ip netns exec #{name} ip -4 addr show scope global | grep inet}
193
- system("#{sudo}rm -f #{path}")
194
- ip = res.strip.split(' ')[1].to_s.sub(%r{/.*$}, '').strip
195
- ip.empty? ? nil : ip
196
- end
197
- end
198
- end
199
-
200
- def sudo
201
- self.class.sudo
202
- end
203
-
204
- # Full path to container
205
- def container_path
206
- Pathname.new(@base_path).join(name)
207
- end
208
- alias_method :path, :container_path
209
-
210
- # Full path to container configuration file
211
- def container_config
212
- container_path.join('config')
213
- end
214
- alias_method :config, :container_config
215
-
216
- def container_rootfs
217
- container_path.join('rootfs')
218
- end
219
- alias_method :rootfs, :container_rootfs
220
-
221
- def expand_path(path)
222
- container_rootfs.join(path)
223
- end
224
-
225
- def state
226
- self.class.info(name)[:state]
227
- end
228
-
229
- def pid
230
- self.class.info(name)[:pid]
231
- end
232
-
233
- # Start the container
234
- def start
235
- run_command("#{sudo}lxc-start -n #{name} -d")
236
- run_command("#{sudo}lxc-wait -n #{name} -s RUNNING", :allow_failure_retry => 2)
237
- end
238
-
239
- # Stop the container
240
- def stop
241
- run_command("#{sudo}lxc-stop -n #{name}", :allow_failure_retry => 3)
242
- run_command("#{sudo}lxc-wait -n #{name} -s STOPPED", :allow_failure_retry => 2)
243
- end
244
-
245
- # Freeze the container
246
- def freeze
247
- run_command("#{sudo}lxc-freeze -n #{name}")
248
- run_command("#{sudo}lxc-wait -n #{name} -s FROZEN", :allow_failure_retry => 2)
249
- end
250
-
251
- # Unfreeze the container
252
- def unfreeze
253
- run_command("#{sudo}lxc-unfreeze -n #{name}")
254
- run_command("#{sudo}lxc-wait -n #{name} -s RUNNING", :allow_failure_retry => 2)
255
- end
256
-
257
- # Shutdown the container
258
- def shutdown
259
- run_command("#{sudo}lxc-shutdown -n #{name}")
260
- run_command("#{sudo}lxc-wait -n #{name} -s STOPPED", :allow_failure => true, :timeout => 120)
261
- # This block is for fedora/centos/anyone else that does not like lxc-shutdown
262
- if(running?)
263
- container_command('shutdown -h now')
264
- run_command("#{sudo}lxc-wait -n #{name} -s STOPPED", :allow_failure => true)
265
- # If still running here, something is wrong
266
- if(running?)
267
- raise "Failed to shutdown container: #{name}"
268
- end
269
- end
270
- end
271
-
272
- def direct_container_command(command, args={})
273
- com = "#{sudo}ssh root@#{args[:ip] || container_ip} -i /opt/hw-lxc-config/id_rsa -oStrictHostKeyChecking=no '#{command}'"
274
- begin
275
- cmd = Mixlib::ShellOut.new(com,
276
- :live_stream => args[:live_stream],
277
- :timeout => args[:timeout] || 1200
278
- )
279
- cmd.run_command
280
- cmd.error!
281
- true
282
- rescue
283
- raise if args[:raise_on_failure]
284
- false
285
- end
286
- end
287
- alias_method :knife_container, :direct_container_command
288
-
289
- # Simple helper to shell out
290
- def run_command(cmd, args={})
291
- retries = args[:allow_failure_retry].to_i
292
- begin
293
- shlout = Mixlib::ShellOut.new(cmd,
294
- :logger => defined?(Chef) ? Chef::Log.logger : log,
295
- :live_stream => STDOUT,
296
- :timeout => args[:timeout] || 1200,
297
- :environment => {'HOME' => detect_home}
298
- )
299
- shlout.run_command
300
- shlout.error!
301
- rescue Mixlib::ShellOut::ShellCommandFailed, CommandFailed, Mixlib::ShellOut::CommandTimeout
302
- if(retries > 0)
303
- log.warn "LXC run command failed: #{cmd}"
304
- log.warn "Retrying command. #{args[:allow_failure_retry].to_i - retries} of #{args[:allow_failure_retry].to_i} retries remain"
305
- sleep(0.3)
306
- retries -= 1
307
- retry
308
- elsif(args[:allow_failure])
309
- true
310
- else
311
- raise
312
- end
313
- end
314
- end
315
-
316
- # Detect HOME environment variable. If not an acceptable
317
- # value, set to /root or /tmp
318
- def detect_home(set_if_missing=false)
319
- if(ENV['HOME'] && Pathname.new(ENV['HOME']).absolute?)
320
- ENV['HOME']
321
- else
322
- home = File.directory?('/root') && File.writable?('/root') ? '/root' : '/tmp'
323
- if(set_if_missing)
324
- ENV['HOME'] = home
325
- end
326
- home
327
- end
328
- end
329
-
330
- # cmd:: Shell command string
331
- # retries:: Number of retry attempts (1 second sleep interval)
332
- # Runs command in container via ssh
333
- def container_command(cmd, retries=1)
334
- begin
335
- detect_home(true)
336
- direct_container_command(cmd,
337
- :ip => container_ip(5),
338
- :live_stream => STDOUT,
339
- :raise_on_failure => true
340
- )
341
- rescue => e
342
- if(retries.to_i > 0)
343
- log.info "Encountered error running container command (#{cmd}): #{e}"
344
- log.info "Retrying command..."
345
- retries = retries.to_i - 1
346
- sleep(1)
347
- retry
348
- else
349
- raise e
350
- end
351
- end
352
- end
353
-
354
- def log
355
- if(defined?(Chef))
356
- Chef::Log
357
- else
358
- unless(@logger)
359
- require 'logger'
360
- @logger = Logger.new('/dev/null')
361
- end
362
- @logger
363
- end
364
- end
365
-
366
- end
@@ -1,40 +0,0 @@
1
- module ChefLxc
2
- module Resource
3
-
4
- def container(arg=nil)
5
- set_or_return(:container, arg, :kind_of => [String], :required => true)
6
- end
7
-
8
- def lxc
9
- @lxc ||= Lxc.new(
10
- @container,
11
- :base_dir => node[:lxc][:container_directory]
12
- )
13
- end
14
-
15
- def path(arg=nil)
16
- arg ? super(arg) : lxc.expand_path(super(arg))
17
- end
18
-
19
- def self.included(base)
20
- base.class_eval do
21
- def initialize(*args)
22
- super
23
- @container = nil
24
- end
25
- end
26
- end
27
- end
28
- end
29
-
30
- class Chef
31
- class Resource
32
- class LxcTemplate < Template
33
- include ChefLxc::Resource
34
- end
35
-
36
- class LxcFile < File
37
- include ChefLxc::Resource
38
- end
39
- end
40
- end
@@ -1,84 +0,0 @@
1
- class LxcFileConfig
2
-
3
- attr_reader :network
4
- attr_reader :base
5
-
6
- class << self
7
- def generate_config(resource)
8
- config = []
9
- config << "lxc.utsname = #{resource.utsname}"
10
- if(resource.aa_profile)
11
- config << "lxc.aa_profile = #{resource.aa_profile}"
12
- end
13
- [resource.network].flatten.each do |net_hash|
14
- nhsh = Mash.new(net_hash)
15
- flags = nhsh.delete(:flags)
16
- %w(type link).each do |k|
17
- config << "lxc.network.#{k} = #{nhsh.delete(k)}" if nhsh[k]
18
- end
19
- nhsh.each_pair do |k,v|
20
- config << "lxc.network.#{k} = #{v}"
21
- end
22
- if(flags)
23
- config << "lxc.network.flags = #{flags}"
24
- end
25
- end
26
- if(resource.cap_drop)
27
- config << "lxc.cap.drop = #{Array(resource.cap_drop).join(' ')}"
28
- end
29
- %w(pts tty arch devttydir mount mount_entry rootfs rootfs_mount pivotdir).each do |k|
30
- config << "lxc.#{k.sub('_', '.')} = #{resource.send(k)}" if resource.send(k)
31
- end
32
- prefix = 'lxc.cgroup'
33
- resource.cgroup.each_pair do |key, value|
34
- if(value.is_a?(Array))
35
- value.each do |val|
36
- config << "#{prefix}.#{key} = #{val}"
37
- end
38
- else
39
- config << "#{prefix}.#{key} = #{value}"
40
- end
41
- end
42
- config.join("\n") + "\n"
43
- end
44
-
45
- end
46
-
47
- def initialize(path)
48
- raise 'LXC config file not found' unless File.exists?(path)
49
- @path = path
50
- @network = []
51
- @base = Mash.new
52
- parse!
53
- end
54
-
55
- private
56
-
57
- def parse!
58
- cur_net = nil
59
- File.readlines(@path).each do |line|
60
- if(line.start_with?('lxc.network'))
61
- parts = line.split('=')
62
- name = parts.first.split('.').last.strip
63
- if(name.to_sym == :type)
64
- @network << cur_net if cur_net
65
- cur_net = Mash.new
66
- end
67
- if(cur_net)
68
- cur_net[name] = parts.last.strip
69
- else
70
- raise "Expecting 'lxc.network.type' to start network config block. Found: 'lxc.network.#{name}'"
71
- end
72
- else
73
- parts = line.split('=')
74
- name = parts.first.sub('lxc.', '').strip
75
- if(@base[name])
76
- @base[name] = [@base[name], parts.last.strip].flatten
77
- else
78
- @base[name] = parts.last
79
- end
80
- end
81
- end
82
- @network << cur_net if cur_net
83
- end
84
- end
@@ -1,51 +0,0 @@
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
@@ -1,12 +0,0 @@
1
- name 'lxc'
2
- maintainer 'Chris Roberts'
3
- maintainer_email 'chrisroberts.code@gmail.com'
4
- license 'Apache 2.0'
5
- description 'Chef driven Linux Containers'
6
- long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
7
- version '1.0.1'
8
-
9
- supports 'ubuntu'
10
-
11
- suggests 'omnibus_updater'
12
- suggests 'bridger'
@@ -1,75 +0,0 @@
1
- require 'securerandom'
2
-
3
- def load_current_resource
4
- @lxc = ::Lxc.new(
5
- new_resource.name,
6
- :base_dir => node[:lxc][:container_directory],
7
- :dnsmasq_lease_file => node[:lxc][:dnsmasq_lease_file]
8
- )
9
- new_resource.utsname new_resource.name unless new_resource.utsname
10
- new_resource.rootfs @lxc.rootfs.to_path unless new_resource.rootfs
11
- new_resource.default_bridge node[:lxc][:bridge] unless new_resource.default_bridge
12
- new_resource.mount @lxc.path.join('fstab').to_path unless new_resource.mount
13
- config = LxcFileConfig.new(@lxc.container_config)
14
- if((new_resource.network.nil? || new_resource.network.empty?))
15
- if(config.network.empty?)
16
- default_net = {
17
- :type => :veth,
18
- :link => new_resource.default_bridge,
19
- :flags => :up,
20
- :hwaddr => "00:16:3e#{SecureRandom.hex(3).gsub(/(..)/, ':\1')}"
21
- }
22
- else
23
- default_net = config.network.first
24
- default_net.delete(:ipv4) if default_net.has_key?(:ipv4)
25
- default_net.merge!(:link => new_resource.default_bridge)
26
- end
27
- new_resource.network(default_net)
28
- else
29
- [new_resource.network].flatten.each_with_index do |net_hash, idx|
30
- if(config.network[idx].nil? || config.network[idx][:hwaddr].nil?)
31
- net_hash[:hwaddr] ||= "00:16:3e#{SecureRandom.hex(3).gsub(/(..)/, ':\1')}"
32
- end
33
- end
34
- end
35
- new_resource.cgroup(
36
- Chef::Mixin::DeepMerge.merge(
37
- Mash.new(
38
- 'devices.deny' => 'a',
39
- 'devices.allow' => [
40
- 'c *:* m',
41
- 'b *:* m',
42
- 'c 1:3 rwm',
43
- 'c 1:5 rwm',
44
- 'c 5:1 rwm',
45
- 'c 5:0 rwm',
46
- 'c 1:9 rwm',
47
- 'c 1:8 rwm',
48
- 'c 136:* rwm',
49
- 'c 5:2 rwm',
50
- 'c 254:0 rwm',
51
- 'c 10:229 rwm',
52
- 'c 10:200 rwm',
53
- 'c 1:7 rwm',
54
- 'c 10:228 rwm',
55
- 'c 10:232 rwm'
56
- ]
57
- ),
58
- new_resource.cgroup
59
- )
60
- )
61
- end
62
-
63
- action :create do
64
- _lxc = @lxc
65
-
66
- directory @lxc.path.to_path do
67
- action :create
68
- end
69
-
70
- file "lxc update_config[#{new_resource.utsname}]" do
71
- path _lxc.container_config.to_path
72
- content LxcFileConfig.generate_config(new_resource)
73
- mode 0644
74
- end
75
- end