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 WarnNetworks
|
||||
b.use ForwardPorts
|
||||
b.use PrivateNetworks
|
||||
b.use Boot
|
||||
b.use Builtin::WaitForCommunicator
|
||||
b.use PrivateNetworks
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -127,12 +127,12 @@ module Vagrant
|
|||
|
||||
b2.use ClearForwardedPorts
|
||||
b2.use RemoveTemporaryFiles
|
||||
b2.use GcPrivateNetworkBridges
|
||||
b2.use Builtin::Call, Builtin::GracefulHalt, :stopped, :running do |env2, b3|
|
||||
if !env2[:result]
|
||||
b3.use ForcedHalt
|
||||
end
|
||||
end
|
||||
b2.use GcPrivateNetworkBridges
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -147,7 +147,6 @@ module Vagrant
|
|||
next
|
||||
end
|
||||
|
||||
# TODO: Use Vagrant's built in action once we drop support for vagrant 1.2
|
||||
b2.use Builtin::Call, DestroyConfirm do |env2, b3|
|
||||
if env2[:result]
|
||||
b3.use Builtin::ConfigValidate
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
# sudo ifconfig br1 down && sudo brctl delbr br1
|
||||
|
||||
module Vagrant
|
||||
module LXC
|
||||
module Action
|
||||
|
@ -9,11 +7,38 @@ module Vagrant
|
|||
end
|
||||
|
||||
def call(env)
|
||||
if env[:machine].provider.state.id != :running
|
||||
puts 'Cleanup bridges!'
|
||||
end
|
||||
was_running = env[:machine].provider.state.id == :running
|
||||
|
||||
# Continue execution, we need the container to be stopped
|
||||
@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
|
||||
|
|
|
@ -10,6 +10,7 @@ module Vagrant
|
|||
@app.call(env)
|
||||
|
||||
if private_network_configured?(env[:machine].config)
|
||||
env[:ui].output(I18n.t("vagrant_lxc.messages.setup_private_network"))
|
||||
configure_private_networks(env)
|
||||
end
|
||||
end
|
||||
|
@ -27,50 +28,15 @@ module Vagrant
|
|||
container_name = env[:machine].provider.driver.container_name
|
||||
ip = config[: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!
|
||||
configure_single_network(bridge, bridge_ip, container_name, ip)
|
||||
env[:machine].provider.driver.configure_private_network(bridge, bridge_ip, container_name, ip)
|
||||
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)
|
||||
ip.sub(/^(\d+\.\d+\.\d+)\.\d+/, '\1.254')
|
||||
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
|
||||
|
|
|
@ -46,8 +46,9 @@ module Vagrant
|
|||
wrapper = Tempfile.new('lxc-wrapper').tap do |file|
|
||||
template = Vagrant::Util::TemplateRenderer.new(
|
||||
'sudoers.rb',
|
||||
:template_root => Vagrant::LXC.source_root.join('templates').to_s,
|
||||
:cmd_paths => build_cmd_paths_hash
|
||||
:template_root => Vagrant::LXC.source_root.join('templates').to_s,
|
||||
:cmd_paths => build_cmd_paths_hash,
|
||||
:pipework_regex => "#{ENV['HOME']}/\.vagrant\.d/gems/gems/vagrant-lxc.+/scripts/pipework"
|
||||
)
|
||||
file.puts template.render
|
||||
end
|
||||
|
@ -78,7 +79,7 @@ module Vagrant
|
|||
|
||||
def build_cmd_paths_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
|
||||
end
|
||||
hash['lxc_bin'] = Pathname(`which lxc-create`.strip).parent.to_s
|
||||
|
|
|
@ -126,6 +126,52 @@ module Vagrant
|
|||
@cli.attach(*command)
|
||||
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
|
||||
@version ||= @cli.version
|
||||
end
|
||||
|
|
|
@ -21,6 +21,10 @@ en:
|
|||
warn_owner: |-
|
||||
Warning! The LXC provider doesn't support the :owner parameter for synced
|
||||
folders. It will be silently ignored.
|
||||
setup_private_network: |-
|
||||
Setting up private networks...
|
||||
remove_bridge: |-
|
||||
Removing bridge '%{name}'...
|
||||
|
||||
vagrant:
|
||||
commands:
|
||||
|
|
|
@ -4,24 +4,36 @@
|
|||
class Whitelist
|
||||
class << self
|
||||
def add(command, *args)
|
||||
list[command] ||= []
|
||||
list[command] << args
|
||||
end
|
||||
|
||||
def add_regex(regex, *args)
|
||||
regex_list << [regex, [args]]
|
||||
end
|
||||
|
||||
def list
|
||||
@list ||= Hash.new do |key, hsh|
|
||||
key[hsh] = []
|
||||
end
|
||||
@list ||= {}
|
||||
end
|
||||
|
||||
def regex_list
|
||||
@regex_list ||= []
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
def run!(argv)
|
||||
begin
|
||||
command, args = `which #{argv.shift}`.chomp, argv || []
|
||||
check!(command, args)
|
||||
puts `#{command} #{args.join(" ")}`
|
||||
system "#{command} #{args.join(" ")}"
|
||||
|
||||
exit_code = $?.to_i
|
||||
exit_code = 1 if exit_code == 256
|
||||
|
@ -92,6 +104,11 @@ Whitelist.add '<%= cmd_paths['rm'] %>', templates_path
|
|||
# - Packaging
|
||||
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}
|
||||
# - 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
|
||||
|
|
Loading…
Reference in a new issue