Module: VagrantDockerNetworksManager::Util
- Defined in:
- lib/vagrant-docker-networks-manager/util.rb
Class Method Summary collapse
- .cidr_overlap?(a, b) ⇒ Boolean
- .container_network_mode(container) ⇒ Object
- .docker_available? ⇒ Boolean
- .docker_network_exists?(name) ⇒ Boolean
-
.docker_subnet_conflicts?(target_cidr, ignore_network: nil) ⇒ Boolean
Checks whether a target CIDR overlaps an existing Docker network subnet.
- .each_docker_cidr(ignore_network: nil) ⇒ Object
- .fetch_plugin_network_rows ⇒ Object
- .inspect_networks_batched(ids_or_names) ⇒ Object
- .list_plugin_networks ⇒ Object
- .list_plugin_networks_detailed ⇒ Object
- .normalize_cidr(cidr) ⇒ Object
- .read_network_labels(name) ⇒ Object
- .sh!(*args) ⇒ Object
-
.valid_subnet?(cidr) ⇒ Boolean
Validates that a CIDR is an IPv4 network address, not just an address with a mask.
Class Method Details
.cidr_overlap?(a, b) ⇒ Boolean
122 123 124 125 126 127 128 129 130 |
# File 'lib/vagrant-docker-networks-manager/util.rb', line 122 def cidr_overlap?(a, b) ip_a, mask_a = a.to_s.split("/", 2); ip_b, mask_b = b.to_s.split("/", 2) return false unless mask_a && mask_b na = IPAddr.new(ip_a).mask(mask_a.to_i) nb = IPAddr.new(ip_b).mask(mask_b.to_i) na.include?(IPAddr.new(ip_b)) || nb.include?(IPAddr.new(ip_a)) rescue StandardError false end |
.container_network_mode(container) ⇒ Object
34 35 36 37 |
# File 'lib/vagrant-docker-networks-manager/util.rb', line 34 def container_network_mode(container) out, _err, st = Open3.capture3("docker", "inspect", "--format", "{{.HostConfig.NetworkMode}}", container) st.success? ? out.strip : nil end |
.docker_available? ⇒ Boolean
22 23 24 25 26 27 |
# File 'lib/vagrant-docker-networks-manager/util.rb', line 22 def docker_available? _out, _err, status = Open3.capture3("docker", "info") status.success? rescue StandardError false end |
.docker_network_exists?(name) ⇒ Boolean
29 30 31 32 |
# File 'lib/vagrant-docker-networks-manager/util.rb', line 29 def docker_network_exists?(name) out, _err, st = Open3.capture3("docker", "network", "ls", "--format", "{{.Name}}") st.success? && out.split.include?(name) end |
.docker_subnet_conflicts?(target_cidr, ignore_network: nil) ⇒ Boolean
Checks whether a target CIDR overlaps an existing Docker network subnet.
Compares normalized network CIDRs, not raw strings, so equivalent subnets and overlaps are caught before Docker returns a late create failure.
153 154 155 156 157 |
# File 'lib/vagrant-docker-networks-manager/util.rb', line 153 def docker_subnet_conflicts?(target_cidr, ignore_network: nil) t_norm = normalize_cidr(target_cidr) return false unless t_norm each_docker_cidr(ignore_network: ignore_network).any? { |c| cidr_overlap?(t_norm, c) } end |
.each_docker_cidr(ignore_network: nil) ⇒ Object
132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/vagrant-docker-networks-manager/util.rb', line 132 def each_docker_cidr(ignore_network: nil) out, _e, st = Open3.capture3("docker", "network", "ls", "-q") return [] unless st.success? out.split.each_slice(50).flat_map do |chunk| o, _e2, st2 = Open3.capture3("docker", "network", "inspect", *chunk) next [] unless st2.success? JSON.parse(o).filter_map do |net| next if ignore_network && net["Name"] == ignore_network (net.dig("IPAM","Config") || []).map { |cfg| normalize_cidr(cfg["Subnet"]) }.compact end.flatten end end |
.fetch_plugin_network_rows ⇒ Object
63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/vagrant-docker-networks-manager/util.rb', line 63 def fetch_plugin_network_rows out, _err, st = Open3.capture3( "docker", "network", "ls", "--filter", "label=com.vagrant.plugin=docker_networks_manager", "--format", "{{.ID}}\t{{.Name}}\t{{.Driver}}\t{{.Scope}}" ) return [] unless st.success? out.lines.map do |line| id, name, driver, scope = line.strip.split("\t", 4) { id: id, name: name, driver: driver, scope: scope } end end |
.inspect_networks_batched(ids_or_names) ⇒ Object
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/vagrant-docker-networks-manager/util.rb', line 45 def inspect_networks_batched(ids_or_names) result = {} ids_or_names.each_slice(50) do |chunk| out, _e, st = Open3.capture3("docker", "network", "inspect", *chunk) next unless st.success? JSON.parse(out).each do |net| subs = (net.dig("IPAM","Config") || []).map { |c| c["Subnet"] }.compact cons = (net["Containers"] || {}).size key = net["Id"] || net["Name"] result[key] = { subnets: subs, containers_count: cons } result[net["Name"]] ||= result[key] end end result rescue StandardError {} end |
.list_plugin_networks ⇒ Object
76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/vagrant-docker-networks-manager/util.rb', line 76 def list_plugin_networks rows = fetch_plugin_network_rows details = inspect_networks_batched(rows.map { |r| r[:name] }) rows.each do |r| subs = details.dig(r[:name], :subnets) || [] r[:subnets] = subs.empty? ? "-" : subs.join(", ") end rows rescue StandardError [] end |
.list_plugin_networks_detailed ⇒ Object
88 89 90 91 92 93 94 95 96 |
# File 'lib/vagrant-docker-networks-manager/util.rb', line 88 def list_plugin_networks_detailed rows = fetch_plugin_network_rows details = inspect_networks_batched(rows.map { |r| r[:name] }) rows.each do |r| r[:subnets] = details.dig(r[:name], :subnets) || [] r[:containers] = details.dig(r[:name], :containers_count) || 0 end rows end |
.normalize_cidr(cidr) ⇒ Object
112 113 114 115 116 117 118 119 120 |
# File 'lib/vagrant-docker-networks-manager/util.rb', line 112 def normalize_cidr(cidr) ip_str, mask_str = cidr.to_s.split("/", 2) return nil unless ip_str && mask_str && mask_str =~ /^\d+$/ && (0..32).include?(mask_str.to_i) ip = IPAddr.new(ip_str) rescue nil return nil unless ip&.ipv4? "#{ip.mask(mask_str.to_i)}/#{mask_str.to_i}" rescue StandardError nil end |
.read_network_labels(name) ⇒ Object
39 40 41 42 43 |
# File 'lib/vagrant-docker-networks-manager/util.rb', line 39 def read_network_labels(name) out, _err, st = Open3.capture3("docker", "network", "inspect", name, "--format", "{{json .Labels}}") return {} unless st.success? JSON.parse(out.to_s.strip) rescue {} end |
.sh!(*args) ⇒ Object
12 13 14 15 16 17 18 19 20 |
# File 'lib/vagrant-docker-networks-manager/util.rb', line 12 def sh!(*args) if ENV["VDNM_VERBOSE"] == "1" printable = ["docker", *args].map(&:to_s).shelljoin $stderr.puts("[VDNM] #{printable}") system("docker", *args) else system("docker", *args, out: File::NULL, err: :out) end end |
.valid_subnet?(cidr) ⇒ Boolean
Validates that a CIDR is an IPv4 network address, not just an address with a mask.
102 103 104 105 106 107 108 109 110 |
# File 'lib/vagrant-docker-networks-manager/util.rb', line 102 def valid_subnet?(cidr) ip_str, mask_str = cidr.to_s.split("/", 2) return false unless ip_str && mask_str && mask_str =~ /^\d+$/ && (0..32).include?(mask_str.to_i) ip = IPAddr.new(ip_str) rescue nil return false unless ip && ip.ipv4? (ip.mask(mask_str.to_i).to_s == ip_str) rescue StandardError false end |