Brian Cain 5ed5868067
Inspect networks before creating new ones
This commit updates the behavior of how the docker provider creates new
docker networks. It looks at each existing network to see if the
requested subnet has already been configured in the docker engine. If
so, Vagrant will use that network rather than creating a new one. This
includes networks not created by Vagrant. Vagrant will not clean up
these networks if created outside of Vagrant.
2019-03-12 10:36:57 -07:00

106 lines
3.6 KiB
Ruby

require 'log4r'
module VagrantPlugins
module DockerProvider
module Action
class Network
def initialize(app, env)
@app = app
@logger = Log4r::Logger.new('vagrant::plugins::docker::network')
@@lock = Mutex.new
end
# @param[Hash] options - options from the network config
# @returns[Array] cli_opts - an array of strings used for the network commnad
def generate_create_cli_arguments(options)
cli_opts = []
ignored_options = ["ip", "protocol", "id", "alias"]
# Splits the networking options to generate the proper CLI flags for docker
options.each do |opt, value|
opt = opt.to_s
if (opt == "type" && value == "dhcp") || ignored_options.include?(opt)
# `docker network create` doesn't care about these options
next
else
cli_opts.concat(["--#{opt}=#{value.to_s}"])
end
end
return cli_opts
end
# @param[Hash] options - options from the network config
# @returns[Array] cli_opts - an array of strings used for the network commnad
def generate_connect_cli_arguments(options)
cli_opts = []
if options[:ip]
cli_opts = ["--ip", options[:ip]]
elsif options[:ip6]
cli_opts = ["--ip6", options[:ip6]]
end
if options[:alias]
cli_opts.concat(["--alias=#{options[:alias]}"])
end
return cli_opts
end
def call(env)
# If we are using a host VM, then don't worry about it
machine = env[:machine]
if machine.provider.host_vm?
@logger.debug("Not setting up networks because docker host_vm is in use")
return @app.call(env)
end
env[:ui].info(I18n.t("docker_provider.network_configure"))
machine.config.vm.networks.each do |type, options|
# We only handle private networks
next if type != :private_network
cli_opts = generate_create_cli_arguments(options)
if options[:subnet]
existing_network = machine.provider.driver.subnet_defined?(options[:subnet])
if !existing_network
network_name = "vagrant_network_#{options[:subnet]}"
else
env[:ui].warn(I18n.t("docker_provider.subnet_exists",
network_name: existing_network,
subnet: options[:subnet]))
network_name = existing_network
end
elsif options[:type] == "dhcp"
network_name = "vagrant_network"
else
raise Errors::NetworkInvalidOption, container: machine.name
end
container_id = machine.id
@@lock.synchronize do
machine.env.lock("docker-network-create", retry: true) do
if !machine.provider.driver.existing_network?(network_name)
@logger.debug("Creating network #{network_name}")
machine.provider.driver.create_network(network_name, cli_opts)
else
@logger.debug("Network #{network_name} already created")
end
end
end
@logger.debug("Connecting network #{network_name} to container guest #{machine.name}")
connect_opts = generate_connect_cli_arguments(options)
machine.provider.driver.connect_network(network_name, container_id, connect_opts)
end
@app.call(env)
end
end
end
end
end