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
@@ -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