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.
This commit is contained in:
parent
2c25cf8d01
commit
5ed5868067
|
@ -27,6 +27,7 @@ module VagrantPlugins
|
|||
network_name = "vagrant_network"
|
||||
end
|
||||
|
||||
# Only cleans up networks defined by Vagrant
|
||||
if machine.provider.driver.existing_network?(network_name) &&
|
||||
!machine.provider.driver.network_used?(network_name)
|
||||
env[:ui].info(I18n.t("docker_provider.network_destroy", network_name: network_name))
|
||||
|
|
|
@ -7,6 +7,7 @@ module VagrantPlugins
|
|||
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
|
||||
|
@ -64,7 +65,15 @@ module VagrantPlugins
|
|||
cli_opts = generate_create_cli_arguments(options)
|
||||
|
||||
if options[:subnet]
|
||||
network_name = "vagrant_network_#{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
|
||||
|
@ -72,11 +81,15 @@ module VagrantPlugins
|
|||
end
|
||||
container_id = machine.id
|
||||
|
||||
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")
|
||||
@@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}")
|
||||
|
|
|
@ -205,7 +205,8 @@ module VagrantPlugins
|
|||
# @param [Array] networks - list of networks to inspect
|
||||
# @param [Array] opts - An array of flags used for listing networks
|
||||
def inspect_network(network, opts=nil)
|
||||
command = ['docker', 'network', 'inspect', network].push(*opts)
|
||||
command = ['docker', 'network', 'inspect'] + Array(network)
|
||||
command = command.push(*opts)
|
||||
output = execute(*command)
|
||||
output
|
||||
end
|
||||
|
@ -246,13 +247,35 @@ module VagrantPlugins
|
|||
# Docker network helpers
|
||||
# ######################
|
||||
|
||||
# @param [String] subnet_string - Subnet to look for
|
||||
def subnet_defined?(subnet_string)
|
||||
all_networks = list_network(["--format={{.Name}}"])
|
||||
all_networks = all_networks.split("\n")
|
||||
|
||||
results = inspect_network(all_networks)
|
||||
begin
|
||||
networks_info = JSON.parse(results)
|
||||
networks_info.each do |network|
|
||||
config = network["IPAM"]["Config"]
|
||||
if (config.size > 0 &&
|
||||
config.first["Subnet"] == subnet_string)
|
||||
@logger.debug("Found existing network #{network["Name"]} already configured with #{subnet_string}")
|
||||
return network["Name"]
|
||||
end
|
||||
end
|
||||
rescue JSON::ParserError => e
|
||||
@logger.warn("Could not properly parse response from `docker network inspect #{all_networks.join(" ")}`")
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
# Looks to see if a docker network has already been defined
|
||||
#
|
||||
# @param [String] network - name of network to look for
|
||||
def existing_network?(network)
|
||||
result = list_network(["--format='{{json .Name}}'"])
|
||||
result = list_network(["--format={{.Name}}"])
|
||||
#TODO: we should be more explicit here if we can
|
||||
result.match?(/\"#{network}\"/)
|
||||
result.match?(/#{network}/)
|
||||
end
|
||||
|
||||
# Returns true or false if network is in use or not.
|
||||
|
|
|
@ -70,6 +70,9 @@ en:
|
|||
ssh_through_host_vm: |-
|
||||
SSH will be proxied through the Docker virtual machine since we're
|
||||
not running Docker natively. This is just a notice, and not an error.
|
||||
subnet_exists: |-
|
||||
A network called '%{network_name}' using subnet '%{subnet}' is already in use.
|
||||
Using '%{network_name}' instead of creating a new network...
|
||||
synced_folders_changed: |-
|
||||
Vagrant has noticed that the synced folder definitions have changed.
|
||||
With Docker, these synced folder changes won't take effect until you
|
||||
|
|
|
@ -61,6 +61,7 @@ describe VagrantPlugins::DockerProvider::Action::Network do
|
|||
allow(driver).to receive(:existing_network?).and_return(false)
|
||||
allow(driver).to receive(:create_network).and_return(true)
|
||||
allow(driver).to receive(:connect_network).and_return(true)
|
||||
allow(driver).to receive(:subnet_defined?).and_return(nil)
|
||||
|
||||
called = false
|
||||
app = ->(*args) { called = true }
|
||||
|
@ -76,6 +77,8 @@ describe VagrantPlugins::DockerProvider::Action::Network do
|
|||
allow(driver).to receive(:existing_network?).and_return(false)
|
||||
allow(driver).to receive(:create_network).and_return(true)
|
||||
allow(driver).to receive(:connect_network).and_return(true)
|
||||
allow(driver).to receive(:subnet_defined?).and_return(nil)
|
||||
|
||||
|
||||
expect(subject).to receive(:generate_create_cli_arguments).
|
||||
with(networks[0][1]).and_return(["--subnet=172.20.0.0/16", "--driver=bridge", "--internal=true"])
|
||||
|
@ -86,6 +89,21 @@ describe VagrantPlugins::DockerProvider::Action::Network do
|
|||
expect(subject).to receive(:generate_connect_cli_arguments).
|
||||
with(networks[1][1]).and_return([])
|
||||
|
||||
expect(driver).to receive(:create_network).twice
|
||||
expect(driver).to receive(:connect_network).twice
|
||||
|
||||
subject.call(env)
|
||||
end
|
||||
|
||||
it "uses an existing network if a matching subnet is found" do
|
||||
allow(driver).to receive(:host_vm?).and_return(false)
|
||||
allow(driver).to receive(:existing_network?).and_return(true)
|
||||
allow(driver).to receive(:create_network).and_return(true)
|
||||
allow(driver).to receive(:connect_network).and_return(true)
|
||||
allow(driver).to receive(:subnet_defined?).and_return("my_cool_subnet_network")
|
||||
|
||||
expect(driver).not_to receive(:create_network)
|
||||
|
||||
subject.call(env)
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in New Issue