class Vagrant::LXC::Driver

Constants

DEFAULT_CONTAINERS_PATH

Default root folder where container configs are stored

TEMPLATES_PATH_LOOKUP

Attributes

container_name[R]
customizations[R]

Public Class Methods

new(container_name, sudo_wrapper, cli = nil) click to toggle source
# File lib/vagrant-lxc/driver.rb, line 24
def initialize(container_name, sudo_wrapper, cli = nil)
  @container_name = container_name
  @sudo_wrapper   = sudo_wrapper
  @cli            = cli || CLI.new(sudo_wrapper, container_name)
  @logger         = Log4r::Logger.new("vagrant::provider::lxc::driver")
  @customizations = []
end

Public Instance Methods

all_containers() click to toggle source
# File lib/vagrant-lxc/driver.rb, line 41
def all_containers
  @cli.list
end
attach(*command) click to toggle source
# File lib/vagrant-lxc/driver.rb, line 139
def attach(*command)
  @cli.attach(*command)
end
base_path() click to toggle source
# File lib/vagrant-lxc/driver.rb, line 45
def base_path
  Pathname.new("#{containers_path}/#{@container_name}")
end
bridge_has_an_ip?(bridge_name) click to toggle source
# File lib/vagrant-lxc/driver.rb, line 167
def bridge_has_an_ip?(bridge_name)
  @logger.info "Checking whether the bridge #{bridge_name} has an IP"
  `ip -4 addr show scope global #{bridge_name}` =~ /^\s+inet ([0-9.]+)\/[0-9]+\s+/
end
bridge_is_in_use?(bridge_name) click to toggle source
# File lib/vagrant-lxc/driver.rb, line 172
def bridge_is_in_use?(bridge_name)
  # REFACTOR: This method is **VERY** hacky
  @logger.info "Checking if bridge #{bridge_name} is in use"
  brctl_output = `brctl show #{bridge_name} 2>/dev/null | tail -n +2 | grep -q veth`
  $?.to_i == 0
end
compress_rootfs() click to toggle source

TODO: This needs to be reviewed and specs needs to be written

# File lib/vagrant-lxc/driver.rb, line 194
def compress_rootfs
  # TODO: Pass in tmpdir so we can clean up from outside
  target_path    = "#{Dir.mktmpdir}/rootfs.tar.gz"

  @logger.info "Compressing '#{rootfs_path}' rootfs to #{target_path}"
  @sudo_wrapper.run('tar', '--numeric-owner', '-cvzf', target_path, '-C',
    rootfs_path.parent.to_s, "./#{rootfs_path.basename.to_s}")

  @logger.info "Changing rootfs tarball owner"
  user_details = Etc.getpwnam(Etc.getlogin)
  @sudo_wrapper.run('chown', "#{user_details.uid}:#{user_details.gid}", target_path)

  target_path
end
config_string() click to toggle source
# File lib/vagrant-lxc/driver.rb, line 75
def config_string
  @sudo_wrapper.run('cat', base_path.join('config').to_s)
end
configure_private_network(bridge_name, bridge_ip, container_name, ip) click to toggle source
# File lib/vagrant-lxc/driver.rb, line 143
def configure_private_network(bridge_name, bridge_ip, container_name, ip)
  @logger.info "Configuring network interface for #{container_name} using #{ip} and bridge #{bridge_name}"
  cmd = [
    Vagrant::LXC.source_root.join('scripts/pipework').to_s,
    bridge_name,
    container_name,
    "#{ip}/24"
  ]
  @sudo_wrapper.run(*cmd)

  if ! bridge_has_an_ip?(bridge_name)
    @logger.info "Adding #{bridge_ip} to the bridge #{bridge_name}"
    cmd = [
      'ip',
      'addr',
      'add',
      "#{bridge_ip}/24",
      'dev',
      bridge_name
    ]
    @sudo_wrapper.run(*cmd)
  end
end
containers_path() click to toggle source

Root folder where container configs are stored

# File lib/vagrant-lxc/driver.rb, line 37
def containers_path
  @containers_path ||= @cli.support_config_command? ? @cli.config('lxc.lxcpath') : DEFAULT_CONTAINERS_PATH
end
create(name, backingstore, backingstore_options, template_path, config_file, template_options = {}) click to toggle source
# File lib/vagrant-lxc/driver.rb, line 79
def create(name, backingstore, backingstore_options, template_path, config_file, template_options = {})
  @cli.name = @container_name = name

  import_template(template_path) do |template_name|
    @logger.debug "Creating container..."
    @cli.create template_name, backingstore, backingstore_options, config_file, template_options
  end
end
destroy() click to toggle source
# File lib/vagrant-lxc/driver.rb, line 131
def destroy
  @cli.destroy
end
forced_halt() click to toggle source
# File lib/vagrant-lxc/driver.rb, line 126
def forced_halt
  @logger.info('Shutting down container...')
  @cli.transition_to(:stopped) { |c| c.stop }
end
mac_address() click to toggle source
# File lib/vagrant-lxc/driver.rb, line 67
def mac_address
  return @mac_address if @mac_address

  if config_string =~ /^lxc\.network\.hwaddr\s*+=\s*+(.+)$/
    @mac_address = $1
  end
end
prune_customizations() click to toggle source
# File lib/vagrant-lxc/driver.rb, line 215
def prune_customizations
  # Use sed to just strip out the block of code which was inserted by Vagrant
  @logger.debug 'Prunning vagrant-lxc customizations'
  contents = config_string
  contents.gsub! /^# VAGRANT-BEGIN(.|\s)*# VAGRANT-END\n/, ''
  write_config(contents)
end
remove_bridge(bridge_name) click to toggle source
# File lib/vagrant-lxc/driver.rb, line 179
def remove_bridge(bridge_name)
  @logger.info "Checking whether bridge #{bridge_name} exists"
  brctl_output = `ifconfig -a | grep -q #{bridge_name}`
  return if $?.to_i != 0

  @logger.info "Removing bridge #{bridge_name}"
  @sudo_wrapper.run('ifconfig', bridge_name, 'down')
  @sudo_wrapper.run('brctl', 'delbr', bridge_name)
end
rootfs_path() click to toggle source
# File lib/vagrant-lxc/driver.rb, line 49
def rootfs_path
  config_entry = config_string.match(/^lxc\.rootfs\s+=\s+(.+)$/)[1]
  case config_entry
  when /^overlayfs:/
    # Split on colon (:), ignoring any colon escaped by an escape character ( \ )
    # Pays attention to when the escape character is itself escaped.
    fs_type, master_path, overlay_path = config_entry.split(/(?<!\\)(?:\\\\)*:/)
    if overlay_path
      Pathname.new(overlay_path)
    else
      # Malformed: fall back to prior behaviour
      Pathname.new(config_entry)
    end
  else
    Pathname.new(config_entry)
  end
end
share_folder(host_path, guest_path, mount_options = nil) click to toggle source
# File lib/vagrant-lxc/driver.rb, line 94
def share_folder(host_path, guest_path, mount_options = nil)
  guest_path      = guest_path.gsub(/^\//, '')
  guest_full_path = rootfs_path.join(guest_path)

  unless guest_full_path.directory?
    begin
      @logger.debug("Guest path doesn't exist, creating: #{guest_full_path}")
      @sudo_wrapper.run('mkdir', '-p', guest_full_path.to_s)
    rescue Errno::EACCES
      raise Vagrant::Errors::SharedFolderCreateFailed, :path => guest_path.to_s
    end
  end

  mount_options = Array(mount_options || ['bind'])
  host_path     = host_path.to_s.gsub(' ', '\\\040')
  guest_path    = guest_path.gsub(' ', '\\\040')
  @customizations << ['mount.entry', "#{host_path} #{guest_path} none #{mount_options.join(',')} 0 0"]
end
share_folders(folders) click to toggle source
# File lib/vagrant-lxc/driver.rb, line 88
def share_folders(folders)
  folders.each do |f|
    share_folder(f[:hostpath], f[:guestpath], f.fetch(:mount_options, 'bind'))
  end
end
start(customizations) click to toggle source
# File lib/vagrant-lxc/driver.rb, line 113
def start(customizations)
  @logger.info('Starting container...')

  if ENV['LXC_START_LOG_FILE']
    extra = ['-o', ENV['LXC_START_LOG_FILE'], '-l', 'DEBUG']
  end

  prune_customizations
  write_customizations(customizations + @customizations)

  @cli.start(extra)
end
state() click to toggle source
# File lib/vagrant-lxc/driver.rb, line 209
def state
  if @container_name
    @cli.state
  end
end
supports_attach?() click to toggle source
# File lib/vagrant-lxc/driver.rb, line 135
def supports_attach?
  @cli.supports_attach?
end
validate!() click to toggle source
# File lib/vagrant-lxc/driver.rb, line 32
def validate!
  raise ContainerNotFound if @container_name && ! @cli.list.include?(@container_name)
end
version() click to toggle source
# File lib/vagrant-lxc/driver.rb, line 189
def version
  @version ||= @cli.version
end

Protected Instance Methods

import_template(path) { |template_name| ... } click to toggle source
# File lib/vagrant-lxc/driver.rb, line 248
def import_template(path)
  template_name     = "vagrant-tmp-#{@container_name}"
  tmp_template_path = templates_path.join("lxc-#{template_name}").to_s

  @logger.info 'Copying LXC template into place'
  @sudo_wrapper.run('cp', path, tmp_template_path)
  @sudo_wrapper.run('chmod', '+x', tmp_template_path)

  yield template_name
ensure
  @logger.info 'Removing LXC template'
  if tmp_template_path
    @sudo_wrapper.run('rm', tmp_template_path)
  end
end
templates_path() click to toggle source
# File lib/vagrant-lxc/driver.rb, line 270
def templates_path
  return @templates_path if @templates_path

  path = TEMPLATES_PATH_LOOKUP.find { |candidate| File.directory?(candidate) }
  if !path
    raise Errors::TemplatesDirMissing.new paths: TEMPLATES_PATH_LOOKUP.inspect
  end

  @templates_path = Pathname(path)
end
write_config(contents) click to toggle source
# File lib/vagrant-lxc/driver.rb, line 238
def write_config(contents)
  Tempfile.new('lxc-config').tap do |file|
    file.chmod 0644
    file.write contents
    file.close
    @sudo_wrapper.run 'cp', '-f', file.path, base_path.join('config').to_s
    @sudo_wrapper.run 'chown', 'root:root', base_path.join('config').to_s
  end
end
write_customizations(customizations) click to toggle source
# File lib/vagrant-lxc/driver.rb, line 225
def write_customizations(customizations)
  customizations = customizations.map do |key, value|
    "lxc.#{key}=#{value}"
  end
  customizations.unshift '# VAGRANT-BEGIN'
  customizations      << "# VAGRANT-END\n"

  contents = config_string
  contents << customizations.join("\n")

  write_config(contents)
end