lib/elecksee/ephemeral.rb in elecksee-1.0.22 vs lib/elecksee/ephemeral.rb in elecksee-1.1.0

- old
+ new

@@ -1,20 +1,13 @@ +require 'elecksee' require 'securerandom' require 'fileutils' require 'tmpdir' require 'etc' -%w( - helpers/base helpers/options helpers/copies lxc - storage/overlay_directory storage/overlay_mount - storage/virtual_device -).each do |path| - require "elecksee/#{path}" -end - class Lxc - + # Create ephemeral containers class Ephemeral include Helpers include Helpers::Options include Helpers::Copies @@ -32,19 +25,31 @@ option :ssh_key, '-S', :string, :default => '/opt/hw-lxc-config/id_rsa', :aliases => 'ssh-key', :desc => 'Deprecated: Provided for compatibility' option :lxc_dir, '-L', :string, :default => '/var/lib/lxc', :aliases => 'lxc-dir', :desc => 'Directory of LXC store' option :tmp_dir, '-T', :string, :default => '/tmp/lxc/ephemerals', :aliases => 'tmp-dir', :desc => 'Directory of ephemeral temp files' option :ephemeral_command, '-C', :string, :aliases => 'command' + # @return [String] name of container attr_reader :name + # @return [TrueClass, FalseClass] enable CLI output attr_reader :cli + # @return [String] hostname of container attr_reader :hostname + # @return [String] path to container attr_reader :path + # @return [Lxc] instance of ephemeral attr_reader :lxc + # @return [Storage::OverlayDirectory, Storage::VirtualDevice] attr_reader :ephemeral_device + # @return [Storage::OverlayMount] attr_reader :ephemeral_overlay + # @return [Array<Storage::VirtualDevice] attr_reader :ephemeral_binds + # Create new instance + # + # @param args [Hash] + # @option args [TrueClass, FalseClass] :cli enable CLI output def initialize(args={}) configure!(args) @cli = args[:cli] @path = command("mktemp -d -p #{lxc_dir} #{original}-XXXXXXXXXXXX", :sudo => true).stdout.strip command("chmod 0755 #{@path}", :sudo => true) @@ -52,23 +57,38 @@ @hostname = @name.gsub(%r{[^A-Za-z0-9\-]}, '') @ephemeral_binds = [] @lxc = nil end + # Trap signals to force cleanup + # + # @return [TrueClass] def register_traps %w(TERM INT QUIT).each do |sig| Signal.trap(sig){ cleanup && raise } end + true end + # Write output to CLI + # + # @return [TrueClass, FalseClass] def cli_output if(cli) puts "New ephemeral container started. (#{name})" puts " - Connect using: sudo ssh -i #{ssh_key} root@#{lxc.container_ip(10)}" + true + else + false end end + # Start the ephemeral container + # + # @return [TrueClass] + # @note generally should not be called directly + # @see start! def start_action begin lxc.start if(ephemeral_command) lxc.wait_for_state(:running) @@ -81,14 +101,23 @@ cleanup end true end + # Create the ephemeral container + # + # @return [TrueClass] def create! setup + true end + # Start the ephemeral container + # + # @param args [Symbol] argument list + # @return [TrueClass] + # @note use :fork to fork startup def start!(*args) register_traps setup if(daemon) if(args.include?(:fork)) @@ -100,12 +129,16 @@ start_action end else start_action end + true end + # Stop container and cleanup ephemeral items + # + # @return [TrueClass, FalseClass] def cleanup lxc.stop @ephemeral_overlay.unmount @ephemeral_binds.map(&:destroy) @ephemeral_device.destroy @@ -118,54 +151,69 @@ end end private + # Setup the ephemeral container resources + # + # @return [TrueClass] def setup create build_overlay update_naming discover_binds apply_custom_networking if ipaddress + true end + # Create the overlay + # + # @return [TrueClass, FalseClass] def build_overlay if(directory) - @ephemeral_device = OverlayDirectory.new(name, :tmp_dir => directory.is_a?(String) ? directory : tmp_dir) + @ephemeral_device = Storage::OverlayDirectory.new(name, :tmp_dir => directory.is_a?(String) ? directory : tmp_dir) else - @ephemeral_device = VirtualDevice.new(name, :size => device, :tmp_fs => !device, :tmp_dir => tmp_dir) + @ephemeral_device = Storage::VirtualDevice.new(name, :size => device, :tmp_fs => !device, :tmp_dir => tmp_dir) @ephemeral_device.mount end - @ephemeral_overlay = OverlayMount.new( + @ephemeral_overlay = Storage::OverlayMount.new( :base => Lxc.new(original).rootfs.to_path, :overlay => ephemeral_device.target_path, :target => lxc.path.join('rootfs').to_path, :overlay_type => union ) @ephemeral_overlay.mount end + # Create the container + # + # @return [TrueClass] def create Dir.glob(File.join(lxc_dir, original, '*')).each do |o_path| next unless File.file?(o_path) command("cp #{o_path} #{File.join(path, File.basename(o_path))}", :sudo => true) end @lxc = Lxc.new(name) command("mkdir -p #{lxc.path.join('rootfs')}", :sudo => true) update_net_hwaddr + true end - # TODO: Discovered binds for ephemeral are all tmpfs for now. - # TODO: We should default to overlay mount, make virt dev optional + # Discover any bind mounts defined + # + # @return [TrueClass] + # @todo discovered binds for ephemeral are all tmpfs for + # now. should default to overlay mount, make virtual + # device and tmpfs optional def discover_binds contents = File.readlines(lxc.path.join('fstab')).each do |line| parts = line.split(' ') if(parts[3] == 'bind') source = parts.first target = parts[1].sub(%r{^.+rootfs/}, '') container_target = lxc.rootfs.join(target).to_path - device = VirtualDevice.new(target.gsub('/', '_'), :tmp_fs => true) + device = Storage::VirtualDevice.new(target.gsub('/', '_'), :tmp_fs => true) device.mount FileUtils.mkdir_p(container_target) ephemeral_binds << device if(union == 'overlayfs') "none #{container_target} overlayfs upperdir=#{device.mount_path},lowerdir=#{source} 0 0" @@ -180,8 +228,10 @@ if(bind) command("mkdir -p #{lxc.rootfs.join(bind).to_path}", :sudo => true) contents << "#{bind} #{lxc.rootfs.join(bind)} none bind 0 0\n" end write_file(lxc.path.join('fstab'), contents.join) + true end + end end