Replace ugly driver builder with a more intelligent approach
References #118
This commit is contained in:
parent
b374bba4ec
commit
0385a64d31
9 changed files with 96 additions and 69 deletions
|
@ -8,6 +8,8 @@ require 'vagrant-lxc/action/destroy'
|
||||||
require 'vagrant-lxc/action/destroy_confirm'
|
require 'vagrant-lxc/action/destroy_confirm'
|
||||||
require 'vagrant-lxc/action/disconnect'
|
require 'vagrant-lxc/action/disconnect'
|
||||||
require 'vagrant-lxc/action/compress_rootfs'
|
require 'vagrant-lxc/action/compress_rootfs'
|
||||||
|
require 'vagrant-lxc/action/fetch_ip_with_lxc_attach'
|
||||||
|
require 'vagrant-lxc/action/fetch_ip_from_dnsmasq_leases'
|
||||||
require 'vagrant-lxc/action/forced_halt'
|
require 'vagrant-lxc/action/forced_halt'
|
||||||
require 'vagrant-lxc/action/forward_ports'
|
require 'vagrant-lxc/action/forward_ports'
|
||||||
require 'vagrant-lxc/action/handle_box_metadata'
|
require 'vagrant-lxc/action/handle_box_metadata'
|
||||||
|
@ -169,6 +171,16 @@ module Vagrant
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# This action is called to read the IP of the container. The IP found
|
||||||
|
# is expected to be put into the `:machine_ip` key.
|
||||||
|
def self.action_fetch_ip
|
||||||
|
Vagrant::Action::Builder.new.tap do |b|
|
||||||
|
b.use Vagrant::Action::Builtin::ConfigValidate
|
||||||
|
b.use FetchIpWithLxcAttach
|
||||||
|
b.use FetchIpFromDnsmasqLeases
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# This is the action that will exec into an SSH shell.
|
# This is the action that will exec into an SSH shell.
|
||||||
def self.action_ssh
|
def self.action_ssh
|
||||||
Vagrant::Action::Builder.new.tap do |b|
|
Vagrant::Action::Builder.new.tap do |b|
|
||||||
|
|
|
@ -1,11 +1,21 @@
|
||||||
module Vagrant
|
module Vagrant
|
||||||
module LXC
|
module LXC
|
||||||
class Driver
|
module Action
|
||||||
module FetchIpFromDsnmasq
|
class FetchIpFromDnsmasqLeases
|
||||||
def assigned_ip
|
def initialize(app, env)
|
||||||
|
@app = app
|
||||||
|
@logger = Log4r::Logger.new("vagrant::lxc::action::fetch_ip_from_dnsmasq_leases")
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
env[:machine_ip] ||= assigned_ip(env)
|
||||||
|
@app.call(env)
|
||||||
|
end
|
||||||
|
|
||||||
|
def assigned_ip(env)
|
||||||
@logger.debug 'Loading ip from dnsmasq leases'
|
@logger.debug 'Loading ip from dnsmasq leases'
|
||||||
|
mac_address = env[:machine].provider.driver.mac_address
|
||||||
ip = nil
|
ip = nil
|
||||||
# TODO: Use Vagrant::Util::Retryable
|
|
||||||
10.times do
|
10.times do
|
||||||
if dnsmasq_leases =~ /#{Regexp.escape mac_address}\s+([0-9.]+)\s+/
|
if dnsmasq_leases =~ /#{Regexp.escape mac_address}\s+([0-9.]+)\s+/
|
||||||
ip = $1.to_s
|
ip = $1.to_s
|
||||||
|
@ -15,15 +25,9 @@ module Vagrant
|
||||||
sleep 2
|
sleep 2
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
# TODO: Raise an user friendly error
|
|
||||||
raise 'Unable to identify container IP!' unless ip
|
|
||||||
ip
|
ip
|
||||||
end
|
end
|
||||||
|
|
||||||
def mac_address
|
|
||||||
@mac_address ||= base_path.join('config').read.match(/^lxc\.network\.hwaddr\s+=\s+(.+)$/)[1]
|
|
||||||
end
|
|
||||||
|
|
||||||
LEASES_PATHS = %w(
|
LEASES_PATHS = %w(
|
||||||
/var/lib/misc/dnsmasq.leases
|
/var/lib/misc/dnsmasq.leases
|
||||||
/var/lib/dnsmasq/dnsmasq.leases
|
/var/lib/dnsmasq/dnsmasq.leases
|
46
lib/vagrant-lxc/action/fetch_ip_with_lxc_attach.rb
Normal file
46
lib/vagrant-lxc/action/fetch_ip_with_lxc_attach.rb
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
module Vagrant
|
||||||
|
module LXC
|
||||||
|
module Action
|
||||||
|
class FetchIpWithLxcAttach
|
||||||
|
# Include this so we can use `Subprocess` more easily.
|
||||||
|
include Vagrant::Util::Retryable
|
||||||
|
|
||||||
|
def initialize(app, env)
|
||||||
|
@app = app
|
||||||
|
@logger = Log4r::Logger.new("vagrant::lxc::action::fetch_ip_with_lxc_attach")
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
env[:machine_ip] ||= assigned_ip(env)
|
||||||
|
@app.call(env)
|
||||||
|
end
|
||||||
|
|
||||||
|
def assigned_ip(env)
|
||||||
|
driver = env[:machine].provider.driver
|
||||||
|
version = driver.version.match(/^(\d+\.\d+)\./)[1].to_f
|
||||||
|
unless version >= 0.8
|
||||||
|
@logger.debug "lxc version does not support the --namespaces argument to lxc-attach"
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
ip = ''
|
||||||
|
retryable(:on => LXC::Errors::ExecuteError, :tries => 10, :sleep => 3) do
|
||||||
|
unless ip = get_container_ip_from_ip_addr(driver)
|
||||||
|
# retry
|
||||||
|
raise LXC::Errors::ExecuteError, :command => "lxc-attach"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
ip
|
||||||
|
end
|
||||||
|
|
||||||
|
# From: https://github.com/lxc/lxc/blob/staging/src/python-lxc/lxc/__init__.py#L371-L385
|
||||||
|
def get_container_ip_from_ip_addr(driver)
|
||||||
|
output = driver.attach '/sbin/ip', '-4', 'addr', 'show', 'scope', 'global', 'eth0', namespaces: 'network'
|
||||||
|
if output =~ /^\s+inet ([0-9.]+)\/[0-9]+\s+/
|
||||||
|
return $1.to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -50,7 +50,7 @@ module Vagrant
|
||||||
redir_pid = redirect_port(
|
redir_pid = redirect_port(
|
||||||
fp[:host_ip],
|
fp[:host_ip],
|
||||||
fp[:host],
|
fp[:host],
|
||||||
fp[:guest_ip] || @env[:machine].provider.driver.assigned_ip,
|
fp[:guest_ip] || @env[:machine].provider.ssh_info[:host],
|
||||||
fp[:guest]
|
fp[:guest]
|
||||||
)
|
)
|
||||||
store_redir_pid(fp[:host], redir_pid)
|
store_redir_pid(fp[:host], redir_pid)
|
||||||
|
|
|
@ -34,6 +34,10 @@ module Vagrant
|
||||||
Pathname.new(base_path.join('config').read.match(/^lxc\.rootfs\s+=\s+(.+)$/)[1])
|
Pathname.new(base_path.join('config').read.match(/^lxc\.rootfs\s+=\s+(.+)$/)[1])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def mac_address
|
||||||
|
@mac_address ||= base_path.join('config').read.match(/^lxc\.network\.hwaddr\s+=\s+(.+)$/)[1]
|
||||||
|
end
|
||||||
|
|
||||||
def create(name, template_path, config_file, template_options = {})
|
def create(name, template_path, config_file, template_options = {})
|
||||||
@cli.name = @container_name = name
|
@cli.name = @container_name = name
|
||||||
|
|
||||||
|
@ -81,6 +85,14 @@ module Vagrant
|
||||||
@cli.destroy
|
@cli.destroy
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def attach(*command)
|
||||||
|
@cli.attach(*command)
|
||||||
|
end
|
||||||
|
|
||||||
|
def version
|
||||||
|
@cli.version
|
||||||
|
end
|
||||||
|
|
||||||
# TODO: This needs to be reviewed and specs needs to be written
|
# TODO: This needs to be reviewed and specs needs to be written
|
||||||
def compress_rootfs
|
def compress_rootfs
|
||||||
rootfs_dirname = File.dirname rootfs_path
|
rootfs_dirname = File.dirname rootfs_path
|
||||||
|
@ -106,9 +118,6 @@ module Vagrant
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def assigned_ip
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
# Root folder where container configs are stored
|
# Root folder where container configs are stored
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
require_relative 'fetch_ip_with_attach'
|
|
||||||
require_relative 'fetch_ip_from_dnsmasq'
|
|
||||||
|
|
||||||
module Vagrant
|
|
||||||
module LXC
|
|
||||||
class Driver
|
|
||||||
class Builder
|
|
||||||
def self.build(id, shell)
|
|
||||||
version = CLI.new(shell).version.match(/^(\d+\.\d+)\./)[1].to_f
|
|
||||||
Driver.new(id, shell).tap do |driver|
|
|
||||||
mod = version >= 0.8 ?
|
|
||||||
Driver::FetchIpWithAttach :
|
|
||||||
Driver::FetchIpFromDsnmasq
|
|
||||||
|
|
||||||
driver.extend(mod)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,29 +0,0 @@
|
||||||
module Vagrant
|
|
||||||
module LXC
|
|
||||||
class Driver
|
|
||||||
module FetchIpWithAttach
|
|
||||||
# Include this so we can use `Subprocess` more easily.
|
|
||||||
include Vagrant::Util::Retryable
|
|
||||||
|
|
||||||
def assigned_ip
|
|
||||||
ip = ''
|
|
||||||
retryable(:on => LXC::Errors::ExecuteError, :tries => 10, :sleep => 3) do
|
|
||||||
unless ip = get_container_ip_from_ip_addr
|
|
||||||
# retry
|
|
||||||
raise LXC::Errors::ExecuteError, :command => "lxc-attach"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
ip
|
|
||||||
end
|
|
||||||
|
|
||||||
# From: https://github.com/lxc/lxc/blob/staging/src/python-lxc/lxc/__init__.py#L371-L385
|
|
||||||
def get_container_ip_from_ip_addr
|
|
||||||
output = @cli.attach '/sbin/ip', '-4', 'addr', 'show', 'scope', 'global', 'eth0', namespaces: 'network'
|
|
||||||
if output =~ /^\s+inet ([0-9.]+)\/[0-9]+\s+/
|
|
||||||
return $1.to_s
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -2,7 +2,6 @@ require "log4r"
|
||||||
|
|
||||||
require "vagrant-lxc/action"
|
require "vagrant-lxc/action"
|
||||||
require "vagrant-lxc/driver"
|
require "vagrant-lxc/driver"
|
||||||
require "vagrant-lxc/driver/builder"
|
|
||||||
require "vagrant-lxc/sudo_wrapper"
|
require "vagrant-lxc/sudo_wrapper"
|
||||||
|
|
||||||
module Vagrant
|
module Vagrant
|
||||||
|
@ -39,7 +38,7 @@ module Vagrant
|
||||||
|
|
||||||
begin
|
begin
|
||||||
@logger.debug("Instantiating the container for: #{id.inspect}")
|
@logger.debug("Instantiating the container for: #{id.inspect}")
|
||||||
@driver = Driver::Builder.build(id, self.sudo_wrapper)
|
@driver = Driver.new(id, self.sudo_wrapper)
|
||||||
@driver.validate!
|
@driver.validate!
|
||||||
rescue Driver::ContainerNotFound
|
rescue Driver::ContainerNotFound
|
||||||
# The container doesn't exist, so we probably have a stale
|
# The container doesn't exist, so we probably have a stale
|
||||||
|
@ -66,8 +65,16 @@ module Vagrant
|
||||||
# we return nil.
|
# we return nil.
|
||||||
return nil if state == :not_created
|
return nil if state == :not_created
|
||||||
|
|
||||||
|
# Run a custom action called "fetch_ip" which does what it says and puts
|
||||||
|
# the IP found into the `:machine_ip` key in the environment.
|
||||||
|
env = @machine.action("fetch_ip")
|
||||||
|
|
||||||
|
# If we were not able to identify the container's IP, we return nil
|
||||||
|
# here and we let Vagrant core deal with it ;)
|
||||||
|
return nil unless env[:machine_ip]
|
||||||
|
|
||||||
{
|
{
|
||||||
:host => @driver.assigned_ip,
|
:host => env[:machine_ip],
|
||||||
:port => @machine.config.ssh.guest_port
|
:port => @machine.config.ssh.guest_port
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,8 +9,7 @@ describe Vagrant::LXC::Action::ForwardPorts do
|
||||||
let(:env) { {machine: machine, ui: double(info: true)} }
|
let(:env) { {machine: machine, ui: double(info: true)} }
|
||||||
let(:machine) { double(:machine) }
|
let(:machine) { double(:machine) }
|
||||||
let!(:data_dir) { Pathname.new(Dir.mktmpdir) }
|
let!(:data_dir) { Pathname.new(Dir.mktmpdir) }
|
||||||
let(:provider) { instance_double('Vagrant::LXC::Provider', driver: driver) }
|
let(:provider) { instance_double('Vagrant::LXC::Provider', ssh_info: {host: container_ip}) }
|
||||||
let(:driver) { instance_double('Vagrant::LXC::Driver', assigned_ip: container_ip) }
|
|
||||||
let(:host_ip) { '127.0.0.1' }
|
let(:host_ip) { '127.0.0.1' }
|
||||||
let(:host_port) { 8080 }
|
let(:host_port) { 8080 }
|
||||||
let(:guest_port) { 80 }
|
let(:guest_port) { 80 }
|
||||||
|
|
Loading…
Reference in a new issue