Experimental support for private networking [GH-298]
This commit is contained in:
parent
bf3a9a5039
commit
447d0dfc42
8 changed files with 111 additions and 53 deletions
|
@ -56,9 +56,9 @@ module Vagrant
|
||||||
b.use Builtin::SetHostname
|
b.use Builtin::SetHostname
|
||||||
b.use WarnNetworks
|
b.use WarnNetworks
|
||||||
b.use ForwardPorts
|
b.use ForwardPorts
|
||||||
|
b.use PrivateNetworks
|
||||||
b.use Boot
|
b.use Boot
|
||||||
b.use Builtin::WaitForCommunicator
|
b.use Builtin::WaitForCommunicator
|
||||||
b.use PrivateNetworks
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -127,12 +127,12 @@ module Vagrant
|
||||||
|
|
||||||
b2.use ClearForwardedPorts
|
b2.use ClearForwardedPorts
|
||||||
b2.use RemoveTemporaryFiles
|
b2.use RemoveTemporaryFiles
|
||||||
|
b2.use GcPrivateNetworkBridges
|
||||||
b2.use Builtin::Call, Builtin::GracefulHalt, :stopped, :running do |env2, b3|
|
b2.use Builtin::Call, Builtin::GracefulHalt, :stopped, :running do |env2, b3|
|
||||||
if !env2[:result]
|
if !env2[:result]
|
||||||
b3.use ForcedHalt
|
b3.use ForcedHalt
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
b2.use GcPrivateNetworkBridges
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -147,7 +147,6 @@ module Vagrant
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
|
||||||
# TODO: Use Vagrant's built in action once we drop support for vagrant 1.2
|
|
||||||
b2.use Builtin::Call, DestroyConfirm do |env2, b3|
|
b2.use Builtin::Call, DestroyConfirm do |env2, b3|
|
||||||
if env2[:result]
|
if env2[:result]
|
||||||
b3.use Builtin::ConfigValidate
|
b3.use Builtin::ConfigValidate
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
# sudo ifconfig br1 down && sudo brctl delbr br1
|
|
||||||
|
|
||||||
module Vagrant
|
module Vagrant
|
||||||
module LXC
|
module LXC
|
||||||
module Action
|
module Action
|
||||||
|
@ -9,11 +7,38 @@ module Vagrant
|
||||||
end
|
end
|
||||||
|
|
||||||
def call(env)
|
def call(env)
|
||||||
if env[:machine].provider.state.id != :running
|
was_running = env[:machine].provider.state.id == :running
|
||||||
puts 'Cleanup bridges!'
|
|
||||||
end
|
|
||||||
|
|
||||||
|
# Continue execution, we need the container to be stopped
|
||||||
@app.call(env)
|
@app.call(env)
|
||||||
|
|
||||||
|
was_running = was_running && env[:machine].provider.state.id != :running
|
||||||
|
|
||||||
|
if was_running && private_network_configured?(env[:machine].config)
|
||||||
|
private_network_configured?(env[:machine].config)
|
||||||
|
remove_bridges_that_are_not_in_use(env)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def private_network_configured?(config)
|
||||||
|
config.vm.networks.find do |type, _|
|
||||||
|
type.to_sym == :private_network
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def remove_bridges_that_are_not_in_use(env)
|
||||||
|
env[:machine].config.vm.networks.find do |type, config|
|
||||||
|
next if type.to_sym != :private_network
|
||||||
|
|
||||||
|
bridge = config.fetch(:lxc__bridge_name)
|
||||||
|
driver = env[:machine].provider.driver
|
||||||
|
|
||||||
|
if ! driver.bridge_is_in_use?(bridge)
|
||||||
|
env[:ui].info I18n.t("vagrant_lxc.messages.remove_bridge", name: bridge)
|
||||||
|
# TODO: Output that bridge is being removed
|
||||||
|
driver.remove_bridge(bridge)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,6 +10,7 @@ module Vagrant
|
||||||
@app.call(env)
|
@app.call(env)
|
||||||
|
|
||||||
if private_network_configured?(env[:machine].config)
|
if private_network_configured?(env[:machine].config)
|
||||||
|
env[:ui].output(I18n.t("vagrant_lxc.messages.setup_private_network"))
|
||||||
configure_private_networks(env)
|
configure_private_networks(env)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -27,50 +28,15 @@ module Vagrant
|
||||||
container_name = env[:machine].provider.driver.container_name
|
container_name = env[:machine].provider.driver.container_name
|
||||||
ip = config[:ip]
|
ip = config[:ip]
|
||||||
bridge_ip = config.fetch(:lxc__bridge_ip) { build_bridge_ip(ip) }
|
bridge_ip = config.fetch(:lxc__bridge_ip) { build_bridge_ip(ip) }
|
||||||
bridge = config.fetch(:lxc__bridge_name) # { build_bridge_name(config.fetch(:lxc__bridge_prefix, 'br'), bridge_ip) }
|
bridge = config.fetch(:lxc__bridge_name)
|
||||||
|
|
||||||
# TODO: ensure_ip_is_not_in_use!
|
env[:machine].provider.driver.configure_private_network(bridge, bridge_ip, container_name, ip)
|
||||||
configure_single_network(bridge, bridge_ip, container_name, ip)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def configure_single_network(bridge, bridge_ip, container_name, ip)
|
|
||||||
cmd = [
|
|
||||||
'sudo',
|
|
||||||
Vagrant::LXC.source_root.join('scripts/private-network').to_s,
|
|
||||||
bridge,
|
|
||||||
container_name,
|
|
||||||
"#{ip}/24"
|
|
||||||
]
|
|
||||||
execute(cmd)
|
|
||||||
|
|
||||||
# TODO: Run only if bridge is not up and move it to the private network script
|
|
||||||
cmd = [
|
|
||||||
'sudo',
|
|
||||||
'ip',
|
|
||||||
'addr',
|
|
||||||
'add',
|
|
||||||
"#{bridge_ip}/24",
|
|
||||||
'dev',
|
|
||||||
bridge
|
|
||||||
]
|
|
||||||
execute(cmd)
|
|
||||||
end
|
|
||||||
|
|
||||||
def execute(cmd)
|
|
||||||
puts cmd.join(' ')
|
|
||||||
system cmd.join(' ')
|
|
||||||
end
|
|
||||||
|
|
||||||
def build_bridge_ip(ip)
|
def build_bridge_ip(ip)
|
||||||
ip.sub(/^(\d+\.\d+\.\d+)\.\d+/, '\1.254')
|
ip.sub(/^(\d+\.\d+\.\d+)\.\d+/, '\1.254')
|
||||||
end
|
end
|
||||||
|
|
||||||
def bridge_name(prefix, bridge_ip)
|
|
||||||
# if a bridge with the provided ip and prefix exist, get its name and return it
|
|
||||||
# if no bridges can be found, grab the max bridge number, increment it and return the new name
|
|
||||||
'br3'
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -46,8 +46,9 @@ module Vagrant
|
||||||
wrapper = Tempfile.new('lxc-wrapper').tap do |file|
|
wrapper = Tempfile.new('lxc-wrapper').tap do |file|
|
||||||
template = Vagrant::Util::TemplateRenderer.new(
|
template = Vagrant::Util::TemplateRenderer.new(
|
||||||
'sudoers.rb',
|
'sudoers.rb',
|
||||||
:template_root => Vagrant::LXC.source_root.join('templates').to_s,
|
:template_root => Vagrant::LXC.source_root.join('templates').to_s,
|
||||||
:cmd_paths => build_cmd_paths_hash
|
:cmd_paths => build_cmd_paths_hash,
|
||||||
|
:pipework_regex => "#{ENV['HOME']}/\.vagrant\.d/gems/gems/vagrant-lxc.+/scripts/pipework"
|
||||||
)
|
)
|
||||||
file.puts template.render
|
file.puts template.render
|
||||||
end
|
end
|
||||||
|
@ -78,7 +79,7 @@ module Vagrant
|
||||||
|
|
||||||
def build_cmd_paths_hash
|
def build_cmd_paths_hash
|
||||||
{}.tap do |hash|
|
{}.tap do |hash|
|
||||||
%w( which cat mkdir cp chown chmod rm tar chown ).each do |cmd|
|
%w( which cat mkdir cp chown chmod rm tar chown ip ifconfig brctl ).each do |cmd|
|
||||||
hash[cmd] = `which #{cmd}`.strip
|
hash[cmd] = `which #{cmd}`.strip
|
||||||
end
|
end
|
||||||
hash['lxc_bin'] = Pathname(`which lxc-create`.strip).parent.to_s
|
hash['lxc_bin'] = Pathname(`which lxc-create`.strip).parent.to_s
|
||||||
|
|
|
@ -126,6 +126,52 @@ module Vagrant
|
||||||
@cli.attach(*command)
|
@cli.attach(*command)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
def version
|
def version
|
||||||
@version ||= @cli.version
|
@version ||= @cli.version
|
||||||
end
|
end
|
||||||
|
|
|
@ -21,6 +21,10 @@ en:
|
||||||
warn_owner: |-
|
warn_owner: |-
|
||||||
Warning! The LXC provider doesn't support the :owner parameter for synced
|
Warning! The LXC provider doesn't support the :owner parameter for synced
|
||||||
folders. It will be silently ignored.
|
folders. It will be silently ignored.
|
||||||
|
setup_private_network: |-
|
||||||
|
Setting up private networks...
|
||||||
|
remove_bridge: |-
|
||||||
|
Removing bridge '%{name}'...
|
||||||
|
|
||||||
vagrant:
|
vagrant:
|
||||||
commands:
|
commands:
|
||||||
|
|
|
@ -4,24 +4,36 @@
|
||||||
class Whitelist
|
class Whitelist
|
||||||
class << self
|
class << self
|
||||||
def add(command, *args)
|
def add(command, *args)
|
||||||
|
list[command] ||= []
|
||||||
list[command] << args
|
list[command] << args
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def add_regex(regex, *args)
|
||||||
|
regex_list << [regex, [args]]
|
||||||
|
end
|
||||||
|
|
||||||
def list
|
def list
|
||||||
@list ||= Hash.new do |key, hsh|
|
@list ||= {}
|
||||||
key[hsh] = []
|
end
|
||||||
end
|
|
||||||
|
def regex_list
|
||||||
|
@regex_list ||= []
|
||||||
end
|
end
|
||||||
|
|
||||||
def allowed(command)
|
def allowed(command)
|
||||||
list[command] || []
|
list[command] || allowed_regex(command) || []
|
||||||
|
end
|
||||||
|
|
||||||
|
def allowed_regex(command)
|
||||||
|
found = regex_list.find { |r| r[0] =~ command }
|
||||||
|
return found[1] if found
|
||||||
end
|
end
|
||||||
|
|
||||||
def run!(argv)
|
def run!(argv)
|
||||||
begin
|
begin
|
||||||
command, args = `which #{argv.shift}`.chomp, argv || []
|
command, args = `which #{argv.shift}`.chomp, argv || []
|
||||||
check!(command, args)
|
check!(command, args)
|
||||||
puts `#{command} #{args.join(" ")}`
|
system "#{command} #{args.join(" ")}"
|
||||||
|
|
||||||
exit_code = $?.to_i
|
exit_code = $?.to_i
|
||||||
exit_code = 1 if exit_code == 256
|
exit_code = 1 if exit_code == 256
|
||||||
|
@ -92,6 +104,11 @@ Whitelist.add '<%= cmd_paths['rm'] %>', templates_path
|
||||||
# - Packaging
|
# - Packaging
|
||||||
Whitelist.add '<%= cmd_paths['tar'] %>', '--numeric-owner', '-cvzf', %r{/tmp/.*/rootfs.tar.gz}, '-C', base_path, './rootfs'
|
Whitelist.add '<%= cmd_paths['tar'] %>', '--numeric-owner', '-cvzf', %r{/tmp/.*/rootfs.tar.gz}, '-C', base_path, './rootfs'
|
||||||
Whitelist.add '<%= cmd_paths['chown'] %>', /\A\d+:\d+\z/, %r{\A/tmp/.*/rootfs\.tar\.gz\z}
|
Whitelist.add '<%= cmd_paths['chown'] %>', /\A\d+:\d+\z/, %r{\A/tmp/.*/rootfs\.tar\.gz\z}
|
||||||
|
# - Private network script and commands
|
||||||
|
Whitelist.add '<%= cmd_paths['ip'] %>', 'addr', 'add', /(\d+|\.)+\/24/, 'dev', /.+/
|
||||||
|
Whitelist.add '<%= cmd_paths['ifconfig'] %>', /.+/, 'down'
|
||||||
|
Whitelist.add '<%= cmd_paths['brctl'] %>', 'delbr', /.+/
|
||||||
|
Whitelist.add_regex %r{<%= pipework_regex %>}, '**'
|
||||||
|
|
||||||
##
|
##
|
||||||
# Commands from driver/cli.rb
|
# Commands from driver/cli.rb
|
||||||
|
|
Loading…
Reference in a new issue