From a645ce3c25ca08072d17d932194847f76cad8772 Mon Sep 17 00:00:00 2001 From: Chris Roberts Date: Tue, 19 Mar 2019 11:29:16 -0700 Subject: [PATCH] Docker provider networking support updates Use `mask` option for defining subnet on network configuration. Allow options to be passed through using hash scoping and docker_network and docker_connect prefixes. Enable public networks. Allow configuration to define pre-existing networks by name. --- plugins/providers/docker/action.rb | 12 +- .../docker/action/connect_networks.rb | 75 ++++ .../docker/action/destroy_network.rb | 28 +- plugins/providers/docker/action/network.rb | 102 ------ .../docker/action/prepare_networks.rb | 335 ++++++++++++++++++ plugins/providers/docker/driver.rb | 99 ++++-- plugins/providers/docker/errors.rb | 8 + templates/locales/en.yml | 2 + templates/locales/providers_docker.yml | 53 ++- 9 files changed, 555 insertions(+), 159 deletions(-) create mode 100644 plugins/providers/docker/action/connect_networks.rb delete mode 100644 plugins/providers/docker/action/network.rb create mode 100644 plugins/providers/docker/action/prepare_networks.rb diff --git a/plugins/providers/docker/action.rb b/plugins/providers/docker/action.rb index 68bb78011..b512da387 100644 --- a/plugins/providers/docker/action.rb +++ b/plugins/providers/docker/action.rb @@ -244,6 +244,7 @@ module VagrantPlugins b2.use PrepareNFSValidIds b2.use SyncedFolderCleanup b2.use PrepareNFSSettings + b2.use PrepareNetworks b2.use Login b2.use Build @@ -266,7 +267,7 @@ module VagrantPlugins end end - b2.use Network + b2.use ConnectNetworks b2.use Start b2.use WaitForRunning @@ -294,6 +295,7 @@ module VagrantPlugins action_root = Pathname.new(File.expand_path("../action", __FILE__)) autoload :Build, action_root.join("build") autoload :CompareSyncedFolders, action_root.join("compare_synced_folders") + autoload :ConnectNetworks, action_root.join("connect_networks") autoload :Create, action_root.join("create") autoload :Destroy, action_root.join("destroy") autoload :DestroyBuildImage, action_root.join("destroy_build_image") @@ -311,13 +313,13 @@ module VagrantPlugins autoload :IsBuild, action_root.join("is_build") autoload :IsHostMachineCreated, action_root.join("is_host_machine_created") autoload :Login, action_root.join("login") - autoload :Pull, action_root.join("pull") - autoload :PrepareSSH, action_root.join("prepare_ssh") - autoload :Stop, action_root.join("stop") - autoload :Network, action_root.join("network") + autoload :PrepareNetworks, action_root.join("prepare_networks") autoload :PrepareNFSValidIds, action_root.join("prepare_nfs_valid_ids") autoload :PrepareNFSSettings, action_root.join("prepare_nfs_settings") + autoload :PrepareSSH, action_root.join("prepare_ssh") + autoload :Pull, action_root.join("pull") autoload :Start, action_root.join("start") + autoload :Stop, action_root.join("stop") autoload :WaitForRunning, action_root.join("wait_for_running") end end diff --git a/plugins/providers/docker/action/connect_networks.rb b/plugins/providers/docker/action/connect_networks.rb new file mode 100644 index 000000000..9f29e2031 --- /dev/null +++ b/plugins/providers/docker/action/connect_networks.rb @@ -0,0 +1,75 @@ +require 'ipaddr' +require 'log4r' + +module VagrantPlugins + module DockerProvider + module Action + class ConnectNetworks + + include Vagrant::Util::ScopedHashOverride + + def initialize(app, env) + @app = app + @logger = Log4r::Logger.new('vagrant::plugins::docker::connectnetworks') + end + + # Generate CLI arguments for creating the docker network. + # + # @param [Hash] options Options from the network config + # @returns[Array Network create arguments + def generate_connect_cli_arguments(options) + options.map do |key, value| + # If value is false, option is not set + next if value == false + # If value is true, consider feature flag with no value + opt = value == true ? [] : [value] + opt.unshift("--#{key.to_s.tr("_", "-")}") + end.flatten.compact + end + + # Execute the action + 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_connect")) + + connections = env[:docker_connects] || {} + + machine.config.vm.networks.each_with_index do |args, idx| + type, options = args + next if type != :private_network && type != :public_network + + network_options = scoped_hash_override(options, :docker_connect) + network_options.delete_if{|k,_| options.key?(k)} + network_name = connections[idx] + + if !network_name + raise Errors::NetworkNameMissing, + index: idx, + container: machine.name + end + + @logger.debug("Connecting network #{network_name} to container guest #{machine.name}") + if options[:ip] + if IPAddr.new(options[:ip]).ipv4? + network_options[:ip] = options[:ip] + else + network_options[:ip6] = options[:ip] + end + end + network_options[:alias] = options[:alias] if options[:alias] + connect_opts = generate_connect_cli_arguments(network_options) + machine.provider.driver.connect_network(network_name, machine.id, connect_opts) + end + + @app.call(env) + end + end + end + end +end diff --git a/plugins/providers/docker/action/destroy_network.rb b/plugins/providers/docker/action/destroy_network.rb index b6feac35e..90e57fc28 100644 --- a/plugins/providers/docker/action/destroy_network.rb +++ b/plugins/providers/docker/action/destroy_network.rb @@ -18,22 +18,22 @@ module VagrantPlugins end machine.config.vm.networks.each do |type, options| - # We only handle private networks - next if type != :private_network + next if type != :private_network && type != :public_network - if options[:subnet] - network_name = "vagrant_network_#{options[:subnet]}" - else - network_name = "vagrant_network" - end + machine.env.lock("docker-network-destroy", retry: true) do + vagrant_networks = machine.provider.driver.list_network_names.find_all do |n| + n.start_with?("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)) - machine.provider.driver.rm_network(network_name) - else - @logger.debug("Network #{network_name} not found") + vagrant_networks.each do |network_name| + if machine.provider.driver.existing_named_network?(network_name) && + !machine.provider.driver.network_used?(network_name) + env[:ui].info(I18n.t("docker_provider.network_destroy", network_name: network_name)) + machine.provider.driver.rm_network(network_name) + else + @logger.debug("Network #{network_name} not found or in use") + end + end end end diff --git a/plugins/providers/docker/action/network.rb b/plugins/providers/docker/action/network.rb deleted file mode 100644 index 80cf0fb82..000000000 --- a/plugins/providers/docker/action/network.rb +++ /dev/null @@ -1,102 +0,0 @@ -require 'log4r' - -module VagrantPlugins - module DockerProvider - module Action - class Network - def initialize(app, env) - @app = app - @logger = Log4r::Logger.new('vagrant::plugins::docker::network') - 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"].map(&:freeze).freeze - - # 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 - - 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 - - @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 diff --git a/plugins/providers/docker/action/prepare_networks.rb b/plugins/providers/docker/action/prepare_networks.rb new file mode 100644 index 000000000..842c69154 --- /dev/null +++ b/plugins/providers/docker/action/prepare_networks.rb @@ -0,0 +1,335 @@ +require 'ipaddr' +require 'log4r' + +module VagrantPlugins + module DockerProvider + module Action + class PrepareNetworks + + include Vagrant::Util::ScopedHashOverride + + def initialize(app, env) + @app = app + @logger = Log4r::Logger.new('vagrant::plugins::docker::preparenetworks') + end + + # Generate CLI arguments for creating the docker network. + # + # @param [Hash] options Options from the network config + # @returns[Array Network create arguments + def generate_create_cli_arguments(options) + options.map do |key, value| + # If value is false, option is not set + next if value == false + # If value is true, consider feature flag with no value + opt = value == true ? [] : [value] + opt.unshift("--#{key.to_s.tr("_", "-")}") + end.flatten.compact + end + + # @return [Array] interface list + def list_interfaces + Socket.getifaddrs.find_all do |i| + i.addr.ip? && !i.addr.ipv4_loopback? && + !i.addr.ipv6_loopback? && !i.addr.ipv6_linklocal? + end + end + + # Validates that a network name exists. If it does not + # exist, an exception is raised. + # + # @param [String] name Name of existing network + # @return [Boolean] + def validate_network_name!(name) + if !env[:machine].provider.driver.existing_named_network?(network_name) + raise Errors::NetworkNameUndefined, + network_name: name + end + true + end + + # Validates that the provided options are compatible with a + # pre-existing network. Raises exceptions on invalid configurations + # + # @param [String] network_name Name of the network + # @param [Hash] root_options Root networking options + # @param [Hash] network_options Docker scoped networking options + # @param [Driver] driver Docker driver + # @return [Boolean] + def validate_network_configuration!(network_name, root_options, network_options, driver) + if root_options[:ip] && + driver.network_containing_address(root_options[:ip]) != network_name + raise Errors::NetworkAddressInvalid, + address: root_options[:ip], + network_name: network_name + end + if network_options[:subnet] && + driver.network_containing_address(network_options[:subnet]) != network_name + raise Errors::NetworkSubnetInvalid, + subnet: network_options[:subnet], + network_name: network_name + end + true + end + + # Generate configuration for private network + # + # @param [Hash] root_options Root networking options + # @param [Hash] net_options Docker scoped networking options + # @param [Hash] env Local call env + # @return [String, Hash] Network name and updated network_options + def process_private_network(root_options, network_options, env) + if root_options[:name] && validate_network_name!(root_options[:name]) + network_name = root_options[:name] + end + + if root_options[:type].to_s == "dhcp" + network_name = "vagrant_network" if !network_name + return [network_name, network_options] + end + + if !root_options[:ip] + raise Errors::NetworkIPAddressRequired + end + + # Validate the IP address + addr = IPAddr.new(root_options[:ip]) + + # If address is ipv6, enable ipv6 support + network_options[:ipv6] = addr.ipv6? + + # If no mask is provided, attempt to locate any existing + # network which contains the assigned IP address + if !root_options[:mask] && !network_name + network_name = env[:machine].provider.driver. + network_containing_address(root_options[:ip]) + # When no existing network is found, we are creating + # a new network. Since no mask was provided, default + # to /24 for ipv4 and /64 for ipv6 + if !network_name + root_options[:mask] = addr.ipv4? ? 24 : 64 + end + end + + # With no network name, process options to find or determine + # name for new network + if !network_name + subnet = IPAddr.new("#{root_options[:ip]}/#{root_options[:mask]}") + network = "#{subnet}/#{root_options[:mask]}" + network_options[:subnet] = network + existing_network = env[:machine].provider.driver. + network_defined?(network) + if !existing_network + network_name = "vagrant_network_#{network}" + else + if !existing_network.to_s.start_with?("vagrant_network") + env[:ui].warn(I18n.t("docker_provider.subnet_exists", + network_name: existing_network, + subnet: network)) + end + network_name = existing_network + end + end + + [network_name, network_options] + end + + # Generate configuration for public network + # + # @param [Hash] root_options Root networking options + # @param [Hash] net_options Docker scoped networking options + # @param [Hash] env Local call env + # @return [String, Hash] Network name and updated network_options + def process_public_network(root_options, net_options, env) + if root_options[:name] && validate_network_name!(root_options[:name]) + network_name = root_options[:name] + end + if !network_name + valid_interfaces = list_interfaces + if valid_interfaces.empty? + raise Errors::NetworkNoInterfaces + elsif valid_interfaces.size == 1 + bridge_interface = valid_interfaces.first + elsif i = valid_interfaces.detect{|i| Array(root_options[:bridge]).include?(i.name) } + bridge_interface = i + end + if !bridge_interface + env[:ui].info(I18n.t("vagrant.actions.vm.bridged_networking.available"), + prefix: false) + valid_interfaces.each_with_index do |int, i| + env[:ui].info("#{i + 1}) #{int.name}", prefix: false) + end + env[:ui].info(I18n.t( + "vagrant.actions.vm.bridged_networking.choice_help") + "\n", + prefix: false + ) + end + while !bridge_interface + choice = env[:ui].ask( + I18n.t("vagrant.actions.vm.bridged_networking.select_interface") + " ", + prefix: false) + bridge_interface = valid_interfaces[choice.to_i - 1] + end + base_opts = Vagrant::Util::HashWithIndifferentAccess.new + base_opts[:opt] = "parent=#{bridge_interface.name}" + subnet = IPAddr.new(bridge_interface.addr.ip_address << + "/" << bridge_interface.netmask.ip_unpack.first) + base_opts[:subnet] = "#{subnet}/#{subnet.prefix}" + subnet_addr = IPAddr.new(base_opts[:subnet]) + base_opts[:driver] = "macvlan" + base_opts[:gateway] = subnet_addr.succ.to_s + base_opts[:ipv6] = subnet_addr.ipv6? + network_options = base_opts.merge(net_options) + + # Check if network already exists for this subnet + network_name = env[:machine].provider.driver. + network_containing_address(network_options[:gateway]) + if !network_name + network_name = "vagrant_network_public_#{bridge_interface.name}" + end + + # If the network doesn't already exist, gather available address range + # within subnet which docker can provide addressing + if !env[:machine].provider.driver.existing_named_network?(network_name) + if !net_options[:gateway] + network_options[:gateway] = request_public_gateway( + network_options, bridge_interface.name, env) + end + network_options[:ip_range] = request_public_iprange( + network_options, bridge_interface.name, env) + end + end + [network_name, network_options] + end + + # Request the gateway address for the public network + # + # @param [Hash] network_options Docker scoped networking options + # @param [String] interface The bridge interface used + # @param [Hash] env Local call env + # @return [String] Gateway address + def request_public_gateway(network_options, interface, env) + subnet = IPAddr.new(network_options[:subnet]) + gateway = nil + while !gateway + gateway = env[:ui].ask(I18n.t( + "docker_provider.network_bridge_gateway_request", + interface: interface, + default_gateway: network_options[:gateway]) + " ", + prefix: false + ).strip + if gateway.empty? + gateway = network_options[:gateway] + end + begin + gateway = IPAddr.new(gateway) + if !subnet.include?(gateway) + env[:ui].warn(I18n.t("docker_provider.network_bridge_gateway_outofbounds", + gateway: gateway, + subnet: network_options[:subnet]) + "\n", prefix: false) + end + rescue IPAddr::InvalidAddressError + env[:ui].warn(I18n.t("docker_provider.network_bridge_gateway_invalid", + gateway: gateway) + "\n", prefix: false) + gateway = nil + end + end + gateway.to_s + end + + # Request the IP range allowed for use by docker when creating a new + # public network + # + # @param [Hash] network_options Docker scoped networking options + # @param [String] interface The bridge interface used + # @param [Hash] env Local call env + # @return [String] Address range + def request_public_iprange(network_options, interface, env) + return network_options[:ip_range] if network_options[:ip_range] + subnet = IPAddr.new(network_options[:subnet]) + env[:ui].info(I18n.t( + "docker_provider.network_bridge_iprange_info") + "\n", + prefix: false + ) + range = nil + while !range + range = env[:ui].ask(I18n.t( + "docker_provider.network_bridge_iprange_request", + interface: interface, + default_range: network_options[:subnet]) + " ", + prefix: false + ).strip + if range.empty? + range = network_options[:subnet] + end + begin + range = IPAddr.new(range) + if !subnet.include?(range) + env[:ui].warn(I18n.t( + "docker_provider.network_bridge_iprange_outofbounds", + subnet: network_options[:subnet], + range: "#{range}/#{range.prefix}" + ) + "\n", prefix: false) + range = nil + end + rescue IPAddr::InvalidAddressError + env[:ui].warn(I18n.t( + "docker_provider.network_bridge_iprange_invalid", + range: range) + "\n", prefix: false) + range = nil + end + end + "#{range}/#{range.prefix}" + end + + # Execute the action + 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 + + connections = {} + machine.env.lock("docker-network-create", retry: true) do + env[:ui].info(I18n.t("docker_provider.network_create")) + machine.config.vm.networks.each_with_index do |net_info, net_idx| + type, options = net_info + network_options = scoped_hash_override(options, :docker_network) + network_options.delete_if{|k,_| options.key?(k)} + + case type + when :public_network + network_name, network_options = process_public_network( + options, network_options, env) + when :private_network + network_name, network_options = process_private_network( + options, network_options, env) + else + next # unsupported type so ignore + end + + if !network_name + raise Errors::NetworkInvalidOption, container: machine.name + end + + if !machine.provider.driver.existing_named_network?(network_name) + @logger.debug("Creating network #{network_name}") + cli_opts = generate_create_cli_arguments(network_options) + machine.provider.driver.create_network(network_name, cli_opts) + else + @logger.debug("Network #{network_name} already created") + validate_network_configuration!(network_name, options, network_options, machine.provider.driver) + end + connections[net_idx] = network_name + end + end + + env[:docker_connects] = connections + @app.call(env) + end + end + end + end +end diff --git a/plugins/providers/docker/driver.rb b/plugins/providers/docker/driver.rb index dbe43abf1..7af69efda 100644 --- a/plugins/providers/docker/driver.rb +++ b/plugins/providers/docker/driver.rb @@ -157,14 +157,20 @@ module VagrantPlugins raise if !e.to_s.include?("No such image") end + # Inspect the provided container + # + # @param [String] cid ID or name of container + # @return [Hash] def inspect_container(cid) JSON.parse(execute('docker', 'inspect', cid)).first end + # @return [Array] list of all container IDs def all_containers execute('docker', 'ps', '-a', '-q', '--no-trunc').to_s.split end + # @return [String] IP address of the docker bridge def docker_bridge_ip output = execute('/sbin/ip', '-4', 'addr', 'show', 'scope', 'global', 'docker0') if output =~ /^\s+inet ([0-9.]+)\/[0-9]+\s+/ @@ -206,12 +212,18 @@ module VagrantPlugins command = ['docker', 'network', 'inspect'] + Array(network) command = command.push(*opts) output = execute(*command) - output + begin + JSON.load(output) + rescue JSON::ParseError + @logger.warn("Failed to parse network inspection of network: #{network}") + @logger.debug("Failed network output content: `#{output.inspect}`") + nil + end end - # @param [Array] opts - An array of flags used for listing networks - def list_network(opts=nil) - command = ['docker', 'network', 'ls'].push(*opts) + # @param [String] opts - Flags used for listing networks + def list_network(*opts) + command = ['docker', 'network', 'ls', *opts] output = execute(*command) output end @@ -226,12 +238,11 @@ module VagrantPlugins output end - # TODO: Note...cli can optionally take a list of networks to delete. - # We might need this later, but for now our helper takes 1 network at a time + # Delete network(s) # # @param [String] network - name of network to remove - def rm_network(network) - command = ['docker', 'network', 'rm', network] + def rm_network(*network) + command = ['docker', 'network', 'rm', *network] output = execute(*command) output end @@ -246,34 +257,55 @@ module VagrantPlugins # ###################### # @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") + def network_defined?(subnet_string) + all_networks = list_network_names - 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 + network_info = inspect_network(all_networks) + network_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 - 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 + # Locate network which contains given address # - # @param [String] network - name of network to look for - def existing_network?(network) - result = list_network(["--format={{.Name}}"]) - #TODO: we should be more explicit here if we can - result.match?(/#{network}/) + # @param [String] address IP address + # @return [String] network name + def network_containing_address(address) + names = list_network_names + networks = inspect_network(names) + return if !networks + networks.each do |net| + next if !net["IPAM"] + config = net["IPAM"]["Config"] + next if !config || config.size < 1 + config.each do |opts| + subnet = IPAddr.new(opts["Subnet"]) + if subnet.include?(address) + return net["Name"] + end + end + end + nil + end + + # Looks to see if a docker network has already been defined + # with the given name + # + # @param [String] network_name - name of network to look for + def existing_named_network?(network_name) + result = list_network_names + result.any?{|net_name| net_name == network_name} + end + + # @return [Array] list of all docker networks + def list_network_names + list_network("--format={{.Name}}").split("\n").map(&:strip) end # Returns true or false if network is in use or not. @@ -283,13 +315,8 @@ module VagrantPlugins # @return [Bool,nil] def network_used?(network) result = inspect_network(network) - begin - result = JSON.parse(result) - return result.first["Containers"].size > 0 - rescue JSON::ParserError => e - @logger.warn("Could not properly parse response from `docker network inspect #{network}`") - return nil - end + return nil if !result + return result.first["Containers"].size > 0 end end diff --git a/plugins/providers/docker/errors.rb b/plugins/providers/docker/errors.rb index ffd085427..dc4e2e549 100644 --- a/plugins/providers/docker/errors.rb +++ b/plugins/providers/docker/errors.rb @@ -49,6 +49,14 @@ module VagrantPlugins error_key(:network_invalid_option) end + class NetworkNameMissing < DockerError + error_key(:network_name_missing) + end + + class NetworkNameUndefined < DockerError + error_key(:network_name_undefined) + end + class PackageNotSupported < DockerError error_key(:package_not_supported) end diff --git a/templates/locales/en.yml b/templates/locales/en.yml index 1e4188c5b..5927d6b21 100644 --- a/templates/locales/en.yml +++ b/templates/locales/en.yml @@ -2148,6 +2148,8 @@ en: choice_help: |- When choosing an interface, it is usually the one that is being used to connect to the internet. + select_interface: |- + Which interface should the network bridge to? specific_not_found: |- Specific bridge '%{bridge}' not found. You may be asked to specify which network to bridge to. diff --git a/templates/locales/providers_docker.yml b/templates/locales/providers_docker.yml index 678307f7c..6d5c13635 100644 --- a/templates/locales/providers_docker.yml +++ b/templates/locales/providers_docker.yml @@ -45,8 +45,33 @@ en: This container requires a host VM, and the state of that VM is unknown. Run `vagrant up` to verify that the container and its host VM is running, then try again. - network_configure: |- - Configuring and enabling network interfaces... + network_bridge_gateway_invalid: |- + The provided gateway IP address is invalid (%{gateway}). Please + provide a valid IP address. + network_bridge_gateway_outofbounds: |- + The provided gateway IP (%{gateway}) is not within the defined + subnet (%{subnet}). Please provide an IP address within the + defined subnet. + network_bridge_gateway_request: |- + Gateway IP address for %{interface} interface [%{default_gateway}]: + network_bridge_iprange_info: |- + When an explicit address is not provided to a container attached + to this bridged network, docker will supply an address to the + container. This is independent of the local DHCP service that + may be available on the network. + network_bridge_iprange_invalid: |- + The provided IP address range is invalid (%{range}). Please + provide a valid range. + network_bridge_iprange_outofbounds: |- + The provided IP address range (%{range}) is not within the + defined subnet (%{subnet}). Please provide an address range + within the defined subnet. + network_bridge_iprange_request: |- + Available address range for assignment on %{interface} interface [%{default_range}]: + network_create: |- + Creating and configuring docker networks... + network_connect: |- + Enabling network interfaces... network_destroy: |- Removing network %{network_name} ... not_created_skip: |- @@ -204,9 +229,33 @@ en: is functional and properly configured. Host VM ID: %{id} + network_address_invalid: |- + The configured network address is not valid within the configured + subnet of the defined network. Please update the network settings + and try again. + + Configured address: %{address} + Network name: %{network_name} network_invalid_option: |- Invalid option given for docker network for guest "%{container}". Must specify either a `subnet` or use `type: "dhcp"`. + network_name_missing: |- + The Docker provider is unable to connect the container to the + defined network due to a missing network name. Please validate + your configuration and try again. + + Container: %{container} + Network Number: %{index} + network_name_undefined: |- + The Docker provider was unable to configure networking using the + provided network name `%{network_name}`. Please ensure the network + name is correct and exists, then try again. + network_subnet_invalid: |- + The configured network subnet is not valid for the defined network. + Please update the network settings and try again. + + Configured subnet: %{subnet} + Network name: %{network_name} package_not_supported: |- The "package" command is not supported with the Docker provider. If you'd like to commit or push your Docker container, please SSH