diff --git a/plugins/providers/docker/driver.rb b/plugins/providers/docker/driver.rb index 7af69efda..acad830cf 100644 --- a/plugins/providers/docker/driver.rb +++ b/plugins/providers/docker/driver.rb @@ -214,7 +214,7 @@ module VagrantPlugins output = execute(*command) begin JSON.load(output) - rescue JSON::ParseError + rescue JSON::ParserError @logger.warn("Failed to parse network inspection of network: #{network}") @logger.debug("Failed network output content: `#{output.inspect}`") nil @@ -256,7 +256,11 @@ module VagrantPlugins # Docker network helpers # ###################### + # Determines if a given network has been defined through vagrant with a given + # subnet string + # # @param [String] subnet_string - Subnet to look for + # @return [String] network name - Name of network with requested subnet.`nil` if not found def network_defined?(subnet_string) all_networks = list_network_names @@ -298,6 +302,7 @@ module VagrantPlugins # with the given name # # @param [String] network_name - name of network to look for + # @return [Bool] def existing_named_network?(network_name) result = list_network_names result.any?{|net_name| net_name == network_name} diff --git a/test/unit/plugins/providers/docker/driver_test.rb b/test/unit/plugins/providers/docker/driver_test.rb index d4e66b72e..6504876cb 100644 --- a/test/unit/plugins/providers/docker/driver_test.rb +++ b/test/unit/plugins/providers/docker/driver_test.rb @@ -10,6 +10,149 @@ describe VagrantPlugins::DockerProvider::Driver do allow(subject).to receive(:execute) { |*args| @cmd = args.join(' ') } end + let(:docker_network_struct) { +[ + { + "Name": "bridge", + "Id": "ae74f6cc18bbcde86326937797070b814cc71bfc4a6d8e3e8cf3b2cc5c7f4a7d", + "Created": "2019-03-20T14:10:06.313314662-07:00", + "Scope": "local", + "Driver": "bridge", + "EnableIPv6": false, + "IPAM": { + "Driver": "default", + "Options": nil, + "Config": [ + { + "Subnet": "172.17.0.0/16", + "Gateway": "172.17.0.1" + } + ] + }, + "Internal": false, + "Attachable": false, + "Ingress": false, + "ConfigFrom": { + "Network": "" + }, + "ConfigOnly": false, + "Containers": { + "a1ee9b12bcea8268495b1f43e8d1285df1925b7174a695075f6140adb9415d87": { + "Name": "vagrant-sandbox_docker-1_1553116237", + "EndpointID": "fc1b0ed6e4f700cf88bb26a98a0722655191542e90df3e3492461f4d1f3c0cae", + "MacAddress": "02:42:ac:11:00:02", + "IPv4Address": "172.17.0.2/16", + "IPv6Address": "" + } + }, + "Options": { + "com.docker.network.bridge.default_bridge": "true", + "com.docker.network.bridge.enable_icc": "true", + "com.docker.network.bridge.enable_ip_masquerade": "true", + "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0", + "com.docker.network.bridge.name": "docker0", + "com.docker.network.driver.mtu": "1500" + }, + "Labels": {} + }, + { + "Name": "host", + "Id": "2a2845e77550e33bf3e97bda8b71477ac7d3ccf78bc9102585fdb6056fb84cbf", + "Created": "2018-09-28T10:54:08.633543196-07:00", + "Scope": "local", + "Driver": "host", + "EnableIPv6": false, + "IPAM": { + "Driver": "default", + "Options": nil, + "Config": [] + }, + "Internal": false, + "Attachable": false, + "Ingress": false, + "ConfigFrom": { + "Network": "" + }, + "ConfigOnly": false, + "Containers": {}, + "Options": {}, + "Labels": {} + }, + { + "Name": "vagrant_network", + "Id": "93385d4fd3cf7083a36e62fa72a0ad0a21203d0ddf48409c32b550cd8462b3ba", + "Created": "2019-03-20T14:10:36.828235585-07:00", + "Scope": "local", + "Driver": "bridge", + "EnableIPv6": false, + "IPAM": { + "Driver": "default", + "Options": {}, + "Config": [ + { + "Subnet": "172.18.0.0/16", + "Gateway": "172.18.0.1" + } + ] + }, + "Internal": false, + "Attachable": false, + "Ingress": false, + "ConfigFrom": { + "Network": "" + }, + "ConfigOnly": false, + "Containers": { + "a1ee9b12bcea8268495b1f43e8d1285df1925b7174a695075f6140adb9415d87": { + "Name": "vagrant-sandbox_docker-1_1553116237", + "EndpointID": "9502cd9d37ae6815e3ffeb0bc2de9b84f79e7223e8a1f8f4ccc79459e96c7914", + "MacAddress": "02:42:ac:12:00:02", + "IPv4Address": "172.18.0.2/16", + "IPv6Address": "" + } + }, + "Options": {}, + "Labels": {} + }, + { + "Name": "vagrant_network_172.20.0.0/16", + "Id": "649f0ab3ef0eef6f2a025c0d0398bd7b9b4d05ec88b0d7bd573b44153d903cfb", + "Created": "2019-03-20T14:10:37.088885647-07:00", + "Scope": "local", + "Driver": "bridge", + "EnableIPv6": false, + "IPAM": { + "Driver": "default", + "Options": {}, + "Config": [ + { + "Subnet": "172.20.0.0/16" + } + ] + }, + "Internal": false, + "Attachable": false, + "Ingress": false, + "ConfigFrom": { + "Network": "" + }, + "ConfigOnly": false, + "Containers": { + "a1ee9b12bcea8268495b1f43e8d1285df1925b7174a695075f6140adb9415d87": { + "Name": "vagrant-sandbox_docker-1_1553116237", + "EndpointID": "e19156f8018f283468227fa97c145f4ea0eaba652fb7e977a0c759b1c3ec168a", + "MacAddress": "02:42:ac:14:80:02", + "IPv4Address": "172.20.0.2/16", + "IPv6Address": "" + } + }, + "Options": {}, + "Labels": {} + } +].to_json } + + + describe '#create' do let(:params) { { image: 'jimi/hendrix:electric-ladyland', @@ -295,4 +438,95 @@ describe VagrantPlugins::DockerProvider::Driver do subject.rm_network("vagrant_network") end end + + describe '#network_defined?' do + let(:subnet_string) { "172.20.0.0/16" } + let(:network_names) { ["vagrant_network_172.20.0.0/16", "bridge", "null" ] } + + it "returns network name if defined" do + allow(subject).to receive(:list_network_names).and_return(network_names) + allow(subject).to receive(:inspect_network).and_return(JSON.load(docker_network_struct)) + + network_name = subject.network_defined?(subnet_string) + expect(network_name).to eq("vagrant_network_172.20.0.0/16") + end + + it "returns nil name if not defined" do + allow(subject).to receive(:list_network_names).and_return(network_names) + allow(subject).to receive(:inspect_network).and_return(JSON.load(docker_network_struct)) + + network_name = subject.network_defined?("120.20.0.0/24") + expect(network_name).to eq(nil) + end + end + + describe '#network_containing_address' do + let(:address) { "172.20.128.2" } + let(:network_names) { ["vagrant_network_172.20.0.0/16", "bridge", "null" ] } + + it "returns the network name if it contains the requested address" do + allow(subject).to receive(:list_network_names).and_return(network_names) + allow(subject).to receive(:inspect_network).and_return(JSON.load(docker_network_struct)) + + network_name = subject.network_containing_address(address) + expect(network_name).to eq("vagrant_network_172.20.0.0/16") + end + + it "returns nil if no networks contain the requested address" do + allow(subject).to receive(:list_network_names).and_return(network_names) + allow(subject).to receive(:inspect_network).and_return(JSON.load(docker_network_struct)) + + network_name = subject.network_containing_address("127.0.0.1") + expect(network_name).to eq(nil) + end + end + + describe '#existing_named_network?' do + let(:network_names) { ["vagrant_network_172.20.0.0/16", "bridge", "null" ] } + + it "returns true if the network exists" do + allow(subject).to receive(:list_network_names).and_return(network_names) + + expect(subject.existing_named_network?("vagrant_network_172.20.0.0/16")).to be_truthy + end + + it "returns false if the network does not exist" do + allow(subject).to receive(:list_network_names).and_return(network_names) + + expect(subject.existing_named_network?("vagrant_network_17.0.0/16")).to be_falsey + end + end + + describe '#list_network_names' do + let(:unparsed_network_names) { "vagrant_network_172.20.0.0/16\nbridge\nnull" } + let(:network_names) { ["vagrant_network_172.20.0.0/16", "bridge", "null" ] } + + it "lists the network names" do + allow(subject).to receive(:list_network).with("--format={{.Name}}"). + and_return(unparsed_network_names) + + expect(subject.list_network_names).to eq(network_names) + end + end + + describe '#network_used?' do + let(:network_name) { "vagrant_network_172.20.0.0/16" } + it "returns nil if no networks" do + allow(subject).to receive(:inspect_network).with(network_name).and_return(nil) + + expect(subject.network_used?(network_name)).to eq(nil) + end + + it "returns true if network has containers in use" do + allow(subject).to receive(:inspect_network).with(network_name).and_return([JSON.load(docker_network_struct).last]) + + expect(subject.network_used?(network_name)).to be_truthy + end + + it "returns false if network has containers in use" do + allow(subject).to receive(:inspect_network).with("host").and_return([JSON.load(docker_network_struct)[1]]) + + expect(subject.network_used?("host")).to be_falsey + end + end end