diff options
author | Tim Smith <tsmith@chef.io> | 2016-01-08 11:42:47 -0800 |
---|---|---|
committer | Tim Smith <tsmith@chef.io> | 2016-01-08 11:42:47 -0800 |
commit | b9ee1e1850e3b79d8a81dbe74cdfe409f4728e9e (patch) | |
tree | 8d14704db3acca457cb1ce8a1693dbc70cbe7214 | |
parent | d5ff00ea476aedfc4de92bc14ae00152e7c927de (diff) | |
parent | 920054afc670cf8f7cb09cf368c043136ca1fe98 (diff) | |
download | ohai-b9ee1e1850e3b79d8a81dbe74cdfe409f4728e9e.tar.gz |
Merge pull request #695 from btm/btm/ipv6_mac
Fix detection of mac address on IPv6 only systems
-rw-r--r-- | lib/ohai/mixin/network_constants.rb | 4 | ||||
-rw-r--r-- | lib/ohai/plugins/linux/network.rb | 154 | ||||
-rw-r--r-- | lib/ohai/plugins/network.rb | 91 | ||||
-rw-r--r-- | spec/unit/plugins/linux/network_spec.rb | 39 | ||||
-rw-r--r-- | spec/unit/plugins/network_spec.rb | 147 |
5 files changed, 291 insertions, 144 deletions
diff --git a/lib/ohai/mixin/network_constants.rb b/lib/ohai/mixin/network_constants.rb index 2b47a565..738ee546 100644 --- a/lib/ohai/mixin/network_constants.rb +++ b/lib/ohai/mixin/network_constants.rb @@ -1,6 +1,6 @@ # -# Author:: Serdar Sutay (<serdar@opscode.com>) -# Copyright:: Copyright (c) 2014 Opscode, Inc. +# Author:: Serdar Sutay (<serdar@chef.io>) +# Copyright:: Copyright (c) 2014-2015 Chef Software, Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/lib/ohai/plugins/linux/network.rb b/lib/ohai/plugins/linux/network.rb index 689001dc..0bc90ad1 100644 --- a/lib/ohai/plugins/linux/network.rb +++ b/lib/ohai/plugins/linux/network.rb @@ -138,6 +138,7 @@ Ohai.plugin(:Network) do end.compact.flatten end + # determine layer 1 details for the interface using ethtool def ethernet_layer_one(iface) return iface unless ethtool_binary = find_ethtool_binary keys = %w[ Speed Duplex Port Transceiver Auto-negotiation MDI-X ] @@ -161,6 +162,7 @@ Ohai.plugin(:Network) do iface end + # determine link stats, vlans, queue length, and state for an interface using ip def link_statistics(iface, net_counters) so = shell_out("ip -d -s link") tmp_int = nil @@ -251,7 +253,6 @@ Ohai.plugin(:Network) do end end - def parse_ip_addr_link_line(cint, iface, line) if line =~ /link\/(\w+) ([\da-f\:]+) / iface[cint][:encapsulation] = linux_encaps_lookup($1) @@ -293,7 +294,7 @@ Ohai.plugin(:Network) do iface[cint][:addresses][tmp_addr][:scope] = ($1.eql?("host") ? "Node" : $1.capitalize) end - # If we found we were an an alias interface, restore cint to its original value + # If we found we were an alias interface, restore cint to its original value cint = original_int unless original_int.nil? end cint @@ -307,6 +308,71 @@ Ohai.plugin(:Network) do end end + # returns the macaddress for interface from a hash of interfaces (iface elsewhere in this file) + def get_mac_for_interface(interfaces, interface) + interfaces[interface][:addresses].select{|k,v| v["family"]=="lladdr"}.first.first unless interfaces[interface][:flags].include? "NOARP" + end + + # returns the default route with the lowest metric (unspecified metric is 0) + def choose_default_route(routes) + default_route = routes.select do |r| + r[:destination] == "default" + end.sort do |x,y| + (x[:metric].nil? ? 0 : x[:metric].to_i) <=> (y[:metric].nil? ? 0 : y[:metric].to_i) + end.first + end + + # ipv4/ipv6 routes are different enough that having a single algorithm to select the favored route for both creates unnecessary complexity + # this method attempts to deduce the route that is most important to the user, which is later used to deduce the favored values for {ip,mac,ip6}address + # we only consider routes that are default routes, or those routes that get us to the gateway for a default route + def favored_default_route(routes, iface, default_route, family) + routes.select do |r| + if family[:name] == "inet" + # selecting routes for ipv4 + # using the source field when it's specified : + # 1) in the default route + # 2) in the route entry used to reach the default gateway + r[:src] and # it has a src field + iface[r[:dev]] and # the iface exists + iface[r[:dev]][:addresses].has_key? r[:src] and # the src ip is set on the node + iface[r[:dev]][:addresses][r[:src]][:scope].downcase != "link" and # this isn't a link level addresse + ( r[:destination] == "default" or + ( default_route[:via] and # the default route has a gateway + IPAddress(r[:destination]).include? IPAddress(default_route[:via]) # the route matches the gateway + ) + ) + elsif family[:name] == "inet6" + # selecting routes for ipv6 + iface[r[:dev]] and # the iface exists + iface[r[:dev]][:state] == "up" and # the iface is up + ( r[:destination] == "default" or + ( default_route[:via] and # the default route has a gateway + IPAddress(r[:destination]).include? IPAddress(default_route[:via]) # the route matches the gateway + ) + ) + end + end.sort_by do |r| + # sorting the selected routes: + # - getting default routes first + # - then sort by metric + # - then by prefixlen + [ + r[:destination] == "default" ? 0 : 1, + r[:metric].nil? ? 0 : r[:metric].to_i, + # for some reason IPAddress doesn't accept "::/0", it doesn't like prefix==0 + # just a quick workaround: use 0 if IPAddress fails + begin + IPAddress( r[:destination] == "default" ? family[:default_route] : r[:destination] ).prefix + rescue + 0 + end + ] + end.first + end + + # Both the network plugin and this plugin (linux/network) are run on linux. This plugin runs first. + # If the 'ip' binary is available, this plugin may set {ip,mac,ip6}address. The network plugin should not overwrite these. + # The older code section below that relies on the deprecated net-tools, e.g. netstat and ifconfig, provides less functionality. collect_data(:linux) do require 'ipaddr' @@ -353,18 +419,15 @@ Ohai.plugin(:Network) do routes = parse_routes(family, iface) - # using a temporary var to hold the default route - # in case there are more than 1 default route, sort it by its metric - # and return the first one - # (metric value when unspecified is 0) - default_route = routes.select do |r| - r[:destination] == "default" - end.sort do |x,y| - (x[:metric].nil? ? 0 : x[:metric].to_i) <=> (y[:metric].nil? ? 0 : y[:metric].to_i) - end.first + default_route = choose_default_route(routes) if default_route.nil? or default_route.empty? - Ohai::Log.debug("Unable to determine default #{family[:name]} interface") + attribute_name == if family[:name] == "inet" + "default_interface" + else + "default_#{family[:name]}_interface" + end + Ohai::Log.debug("Unable to determine '#{attribute_name}' as no default routes were found for that interface family") else network["#{default_prefix}_interface"] = default_route[:dev] Ohai::Log.debug("#{default_prefix}_interface set to #{default_route[:dev]}") @@ -373,52 +436,35 @@ Ohai.plugin(:Network) do network["#{default_prefix}_gateway"] = default_route[:via] ? default_route[:via] : family[:default_route].chomp("/0") Ohai::Log.debug("#{default_prefix}_gateway set to #{network["#{default_prefix}_gateway"]}") + # deduce the default route the user most likely cares about to pick {ip,mac,ip6}address below + favored_route = favored_default_route(routes, iface, default_route, family) + + # FIXME: This entire block should go away, and the network plugin should be the sole source of {ip,ip6,mac}address + # since we're at it, let's populate {ip,mac,ip6}address with the best values - # using the source field when it's specified : - # 1) in the default route - # 2) in the route entry used to reach the default gateway - route = routes.select do |r| - # selecting routes - r[:src] and # it has a src field - iface[r[:dev]] and # the iface exists - iface[r[:dev]][:addresses].has_key? r[:src] and # the src ip is set on the node - iface[r[:dev]][:addresses][r[:src]][:scope].downcase != "link" and # this isn't a link level addresse - ( r[:destination] == "default" or - ( default_route[:via] and # the default route has a gateway - IPAddress(r[:destination]).include? IPAddress(default_route[:via]) # the route matches the gateway - ) - ) - end.sort_by do |r| - # sorting the selected routes: - # - getting default routes first - # - then sort by metric - # - then by prefixlen - [ - r[:destination] == "default" ? 0 : 1, - r[:metric].nil? ? 0 : r[:metric].to_i, - # for some reason IPAddress doesn't accept "::/0", it doesn't like prefix==0 - # just a quick workaround: use 0 if IPAddress fails - begin - IPAddress( r[:destination] == "default" ? family[:default_route] : r[:destination] ).prefix - rescue - 0 - end - ] - end.first - - unless route.nil? or route.empty? + # if we don't set these, the network plugin may set them afterwards + if favored_route && !favored_route.empty? if family[:name] == "inet" - ipaddress route[:src] - macaddress iface[route[:dev]][:addresses].select{|k,v| v["family"]=="lladdr"}.first.first unless iface[route[:dev]][:flags].include? "NOARP" - else - ip6address route[:src] + ipaddress favored_route[:src] + m = get_mac_for_interface(iface, favored_route[:dev]) + Ohai::Log.debug("Overwriting macaddress #{macaddress} with #{m} from interface #{favored_route[:dev]}") if macaddress + macaddress m + elsif family[:name] == "inet6" + # this rarely does anything since we rarely have src for ipv6, so this usually falls back on the network plugin + ip6address favored_route[:src] + if macaddress + Ohai::Log.debug("Not setting macaddress from ipv6 interface #{favored_route[:dev]} because macaddress is already set") + else + macaddress get_mac_for_interface(iface, favored_route[:dev]) + end end + else + Ohai::Log.debug("the linux/network plugin was unable to deduce the favored default route for family '#{family[:name]}' despite finding a default route, and is not setting ipaddress/ip6address/macaddress. the network plugin may provide fallbacks.") + Ohai::Log.debug("this potential default route was excluded: #{default_route}") end end - end - - else - + end # end families.each + else # ip binary not available, falling back to net-tools, e.g. route, ifconfig begin so = shell_out("route -n") route_result = so.stdout.split($/).grep( /^0.0.0.0/ )[0].split( /[ \t]+/ ) @@ -502,7 +548,7 @@ Ohai.plugin(:Network) do iface[$4][:arp][$1] = $2.downcase end end - end + end # end "ip else net-tools" block iface = ethernet_layer_one(iface) counters[:network][:interfaces] = net_counters diff --git a/lib/ohai/plugins/network.rb b/lib/ohai/plugins/network.rb index bc95a650..ac55f1b0 100644 --- a/lib/ohai/plugins/network.rb +++ b/lib/ohai/plugins/network.rb @@ -1,14 +1,14 @@ # -# Author:: Adam Jacob (<adam@opscode.com>) -# Copyright:: Copyright (c) 2008 Opscode, Inc. +# Author:: Adam Jacob (<adam@chef.io>) +# Copyright:: Copyright (c) 2008-2015 Chef Software, Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at -# +# # http://www.apache.org/licenses/LICENSE-2.0 -# +# # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -26,19 +26,21 @@ Ohai.plugin(:NetworkAddresses) do depends "network/interfaces" + # from interface data create array of hashes with ipaddress, scope, and iface + # sorted by scope, prefixlen and then ipaddress where longest prefixes first def sorted_ips(family = "inet") - raise "bad family #{family}" unless [ "inet", "inet6" ].include? family + fail "bad family #{family}" unless %w(inet inet6).include? family - # going to use that later to sort by scope + # priority of ipv6 link scopes to sort by later scope_prio = [ "global", "site", "link", "host", "node", nil ] + # grab ipaddress, scope, and iface for sorting later ipaddresses = [] - # ipaddresses going to hold #{family} ipaddresses and their scope Mash[network['interfaces']].each do |iface, iface_v| - next if iface_v.nil? or not iface_v.has_key? 'addresses' + next if iface_v.nil? || !iface_v.has_key?('addresses') iface_v['addresses'].each do |addr, addr_v| next if addr_v.nil? or not addr_v.has_key? "family" or addr_v['family'] != family - ipaddresses << { + ipaddresses << { :ipaddress => addr_v["prefixlen"] ? IPAddress("#{addr}/#{addr_v["prefixlen"]}") : IPAddress("#{addr}/#{addr_v["netmask"]}"), :scope => addr_v["scope"].nil? ? nil : addr_v["scope"].downcase, :iface => iface @@ -49,35 +51,35 @@ Ohai.plugin(:NetworkAddresses) do # sort ip addresses by scope, by prefixlen and then by ip address # 128 - prefixlen: longest prefixes first ipaddresses.sort_by do |v| - [ ( scope_prio.index(v[:scope]) or 999999 ), + [ ( scope_prio.index(v[:scope]) || 999999 ), 128 - v[:ipaddress].prefix.to_i, ( family == "inet" ? v[:ipaddress].to_u32 : v[:ipaddress].to_u128 ) ] end end + # finds ip address / interface for interface with default route based on + # passed in family. returns [ipaddress, interface] uses 1st ip if no default + # route is found def find_ip(family = "inet") - ips=sorted_ips(family) + ips = sorted_ips(family) - # return if there isn't any #{family} address ! + # return if there aren't any #{family} addresses! return [ nil, nil ] if ips.empty? # shortcuts to access default #{family} interface and gateway int_attr = Ohai::Mixin::NetworkConstants::FAMILIES[family] +"_interface" gw_attr = Ohai::Mixin::NetworkConstants::FAMILIES[family] + "_gateway" - # If we have a default interface that has addresses, - # populate the short-cut attributes ipaddress, ip6address and macaddress if network[int_attr] - # working with the address(es) of the default network interface gw_if_ips = ips.select do |v| v[:iface] == network[int_attr] end if gw_if_ips.empty? Ohai::Log.warn("[#{family}] no ip address on #{network[int_attr]}") - elsif network[gw_attr] and - network["interfaces"][network[int_attr]] and + elsif network[gw_attr] && + network["interfaces"][network[int_attr]] && network["interfaces"][network[int_attr]]["addresses"] if [ "0.0.0.0", "::", /^fe80:/ ].any? { |pat| pat === network[gw_attr] } # link level default route @@ -109,15 +111,16 @@ Ohai.plugin(:NetworkAddresses) do [ r[:ipaddress].to_s, r[:iface] ] end + # select mac address of first interface with family of lladdr def find_mac_from_iface(iface) - r = network["interfaces"][iface]["addresses"].select{|k,v| v["family"]=="lladdr"} - r.nil? or r.first.nil? ? nil : r.first.first + r = network["interfaces"][iface]["addresses"].select{|k,v| v["family"] == "lladdr"} + r.nil? || r.first.nil? ? nil : r.first.first end + # address_to_match: String + # ipaddress: IPAddress + # iface: String def network_contains_address(address_to_match, ipaddress, iface) - # address_to_match: String - # ipaddress: IPAddress - # iface: String if peer = network["interfaces"][iface]["addresses"][ipaddress.to_s][:peer] IPAddress(peer) == IPAddress(address_to_match) else @@ -125,11 +128,10 @@ Ohai.plugin(:NetworkAddresses) do end end - # ipaddress, ip6address and macaddress can be set by the #{os}::network plugin - # atm it is expected macaddress is set at the same time than ipaddress - # if ipaddress is set and macaddress is nil, that means the interface - # ipaddress is bound to has the NOARP flag - + # ipaddress, ip6address and macaddress are set for each interface by the + # #{os}::network plugin. atm it is expected macaddress is set at the same + # time as ipaddress. if ipaddress is set and macaddress is nil, that means + # the interface ipaddress is bound to has the NOARP flag collect_data do results = {} @@ -138,39 +140,44 @@ Ohai.plugin(:NetworkAddresses) do counters Mash.new unless counters counters[:network] = Mash.new unless counters[:network] - # inet family is treated before inet6 + # inet family is processed before inet6 to give ipv4 precedence Ohai::Mixin::NetworkConstants::FAMILIES.keys.sort.each do |family| r = {} - ( r["ip"], r["iface"] ) = find_ip(family) + # find the ip/interface with the default route for this family + (r["ip"], r["iface"]) = find_ip(family) r["mac"] = find_mac_from_iface(r["iface"]) unless r["iface"].nil? # don't overwrite attributes if they've already been set by the "#{os}::network" plugin - if family == "inet" and ipaddress.nil? + if (family == "inet") && ipaddress.nil? if r["ip"].nil? Ohai::Log.warn("unable to detect ipaddress") - # i don't issue this warning if r["ip"] exists and r["mac"].nil? - # as it could be a valid setup with a NOARP default_interface - Ohai::Log.warn("unable to detect macaddress") else ipaddress r["ip"] - macaddress r["mac"] end - elsif family == "inet6" and ip6address.nil? + elsif (family == "inet6") && ip6address.nil? if r["ip"].nil? Ohai::Log.debug("unable to detect ip6address") else ip6address r["ip"] - if r["mac"] and macaddress.nil? and ipaddress.nil? - Ohai::Log.debug("macaddress set to #{r["mac"]} from the ipv6 setup") - macaddress r["mac"] - end end end + + # set the macaddress [only if we haven't already]. this allows the #{os}::network plugin to set macaddress + # otherwise we set macaddress on a first-found basis (and we started with ipv4) + if macaddress.nil? + if r["mac"] + Ohai::Log.debug("setting macaddress to '#{r["mac"]}' from interface '#{r["iface"]}' for family '#{family}'") + macaddress r["mac"] + else + Ohai::Log.debug("unable to detect macaddress for family '#{family}'") + end + end + results[family] = r end - if results["inet"]["iface"] and results["inet6"]["iface"] and - results["inet"]["iface"] != results["inet6"]["iface"] - Ohai::Log.debug("ipaddress and ip6address are set from different interfaces (#{results["inet"]["iface"]} & #{results["inet6"]["iface"]}), macaddress has been set using the ipaddress interface") + if results["inet"]["iface"] && results["inet6"]["iface"] && + (results["inet"]["iface"] != results["inet6"]["iface"]) + Ohai::Log.debug("ipaddress and ip6address are set from different interfaces (#{results["inet"]["iface"]} & #{results["inet6"]["iface"]})") end end end diff --git a/spec/unit/plugins/linux/network_spec.rb b/spec/unit/plugins/linux/network_spec.rb index de5a89ce..ab9387ef 100644 --- a/spec/unit/plugins/linux/network_spec.rb +++ b/spec/unit/plugins/linux/network_spec.rb @@ -1,7 +1,7 @@ # # Author:: Caleb Tennis <caleb.tennis@gmail.com> # Author:: Chris Read <chris.read@gmail.com> -# Copyright:: Copyright (c) 2011 Opscode, Inc. +# Copyright:: Copyright (c) 2011-2015 Chef Software, Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -663,7 +663,14 @@ Destination Gateway Genmask Flags Metric Ref Use Iface expect(plugin['network']['interfaces']['eth0.11']['routes']).to include Mash.new( :destination => "default", :via => "1111:2222:3333:4444::1", :metric => "1024", :family => "inet6") end - describe "when there isn't a source field in route entries " do + describe "when there isn't a source field in route entries and no ipv6 default routes" do + let(:linux_ip_route_inet6) { +'fe80::/64 dev eth0 proto kernel metric 256 +fe80::/64 dev eth0.11 proto kernel metric 256 +1111:2222:3333:4444::/64 dev eth0.11 metric 1024 expires 86023sec +' + } + before(:each) do plugin.run end @@ -798,7 +805,7 @@ default via 1111:2222:3333:4444::ffff dev eth0.11 metric 1023 src 1111:2222:333 end end - describe "when there's a source field in a local route entry " do + describe "when there's a source field in a local route entry but it isnt in the default route" do let(:linux_ip_route) { '10.116.201.0/24 dev eth0 proto kernel src 10.116.201.76 192.168.5.0/24 dev eth0 proto kernel src 192.168.5.1 @@ -828,18 +835,34 @@ default via 1111:2222:3333:4444::1 dev eth0.11 metric 1024 expect(plugin['ipaddress']).to eq("10.116.201.76") end + # without a source address on the default route we cannot pick the an ipv6 address from the interface + # In the future an RFC6724 compliant process should choose ip6address in the network plugin + it "does not set ip6address" do + plugin.run + expect(plugin['ip6address']).to eq(nil) + end + + context "with only ipv6 routes" do + let(:linux_ip_route) { '' } + + it "sets macaddress to the mac address of the ip6 default interface" do + expect(plugin['macaddress']).to eq("00:AA:BB:CC:DD:EE") + end + end + describe "when about to set macaddress" do it "sets macaddress" do plugin.run expect(plugin['macaddress']).to eq("12:31:3D:02:BE:A2") end - describe "when then interface has the NOARP flag" do + context "when then ipv4 interface has the NOARP flag and no ipv6 routes exist" do let(:linux_ip_route) { '10.118.19.1 dev tun0 proto kernel src 10.118.19.39 default via 172.16.19.1 dev tun0 ' } + let(:linux_ip_route_inet6) { '' } it "completes the run" do expect(Ohai::Log).not_to receive(:debug).with(/Plugin linux::network threw exception/) @@ -853,11 +876,6 @@ default via 172.16.19.1 dev tun0 end end end - - it "sets ip6address" do - plugin.run - expect(plugin['ip6address']).to eq("1111:2222:3333:4444::3") - end end describe "with a link level default route" do @@ -950,6 +968,9 @@ fe80::/64 dev eth0.11 proto kernel metric 256 inet6 2001:44b8:4160:8f00:a00:27ff:fe13:eacd/64 scope global dynamic valid_lft 6128sec preferred_lft 2526sec '} + # We don't have the corresponding ipv6 data for these tests + let(:linux_ip_route_inet6) { '' } + let(:linux_ip_inet6_neighbor_show) { '' } before(:each) do allow(plugin).to receive(:is_openvz?).and_return true diff --git a/spec/unit/plugins/network_spec.rb b/spec/unit/plugins/network_spec.rb index 03ea6b81..5b426334 100644 --- a/spec/unit/plugins/network_spec.rb +++ b/spec/unit/plugins/network_spec.rb @@ -26,8 +26,8 @@ def it_doesnt_fail end end +# basic sanity check that is called in all describes below def it_populates_ipaddress_attributes - source = caller[0] it "populates ipaddress, macaddress and ip6address" do @@ -43,11 +43,11 @@ def it_populates_ipaddress_attributes raise end end - end describe Ohai::System, "Network Plugin" do + # output of network plugins on particular platforms to mock plugin runs basic_data = { "freebsd" => { "network" => { @@ -57,7 +57,9 @@ describe Ohai::System, "Network Plugin" do "number" => "0", "flags" => ["UP", "BROADCAST", "RUNNING", "SIMPLEX", "MULTICAST"], "addresses" => { - "00:00:24:c9:5e:b8" => {"family" => "lladdr"}, + "00:00:24:c9:5e:b8" => { + "family" => "lladdr" + }, "fe80::200:24ff:fec9:5eb8" => { "family" => "inet6", "zoneid" => "vr0", @@ -80,7 +82,9 @@ describe Ohai::System, "Network Plugin" do "number" => "1", "flags" => ["UP", "BROADCAST", "RUNNING", "PROMISC", "SIMPLEX", "MULTICAST"], "addresses" => { - "00:00:24:c9:5e:b9" => {"family" => "lladdr"}, + "00:00:24:c9:5e:b9" => { + "family" => "lladdr" + }, "fe80::200:24ff:fec9:5eb9" => { "family" => "inet6", "zoneid" => "vr1", @@ -94,7 +98,9 @@ describe Ohai::System, "Network Plugin" do "number" => "2", "flags" => ["UP", "BROADCAST", "RUNNING", "PROMISC", "SIMPLEX", "MULTICAST"], "addresses" => { - "00:00:24:c9:5e:ba" => {"family" => "lladdr"}, + "00:00:24:c9:5e:ba" => { + "family" => "lladdr" + }, "fe80::200:24ff:fec9:5eba" => { "family" => "inet6", "zoneid" => "vr2", @@ -108,7 +114,9 @@ describe Ohai::System, "Network Plugin" do "number" => "3", "flags" => ["UP", "BROADCAST", "RUNNING", "PROMISC", "SIMPLEX", "MULTICAST"], "addresses" => { - "00:00:24:c9:5e:bb" => {"family" => "lladdr"}, + "00:00:24:c9:5e:bb" => { + "family" => "lladdr" + }, "fe80::200:24ff:fec9:5ebb" => { "family" => "inet6", "zoneid" => "vr3", @@ -128,8 +136,14 @@ describe Ohai::System, "Network Plugin" do "number" => "0", "flags" => ["UP", "LOOPBACK", "RUNNING", "MULTICAST"], "addresses" => { - "127.0.0.1" => {"family" => "inet", "netmask" => "255.0.0.0"}, - "::1" => {"family" => "inet6", "prefixlen" => "128"}, + "127.0.0.1" => { + "family" => "inet", + "netmask" => "255.0.0.0" + }, + "::1" => { + "family" => "inet6", + "prefixlen" => "128" + }, "fe80::1" => { "family" => "inet6", "zoneid" => "lo0", @@ -143,13 +157,18 @@ describe Ohai::System, "Network Plugin" do "number" => "0", "flags" => ["LEARNING", "DISCOVER", "AUTOEDGE", "AUTOPTP"], "addresses" => { - "02:20:6f:d2:c4:00" => {"family"=>"lladdr"}, + "02:20:6f:d2:c4:00" => { + "family"=>"lladdr" + }, "192.168.2.1" => { "family" => "inet", "netmask" => "255.255.255.0", "broadcast" => "192.168.2.255" }, - "2001:470:d:cb4::1" => {"family" => "inet6", "prefixlen" => "64"}, + "2001:470:d:cb4::1" => { + "family" => "inet6", + "prefixlen" => "64" + }, "fe80::cafe:babe:dead:beef" => { "family" => "inet6", "zoneid" => "bridge0", @@ -183,12 +202,14 @@ describe Ohai::System, "Network Plugin" do } }, "default_gateway" => "76.91.0.1", - "default_interface" => "vr0" + "default_interface" => "vr0", + "default_inet6_gateway" => "2001:470:d:cb4::2", + "default_inet6_interface" => "bridge0" } }, "linux" => { "network" => { - # pp Hash[node['network']] from shef to get the network data + # pp Hash[node['network']] from chef-shell to get the network data # have just removed the neighbour and route entries by hand "interfaces" => { "lo" => { @@ -207,7 +228,8 @@ describe Ohai::System, "Network Plugin" do } }, "mtu" => "16436", - "encapsulation" => "Loopback" + "encapsulation" => "Loopback", + "state" => "unknown" }, "eth0" => { "flags" => ["BROADCAST", "MULTICAST", "UP"], @@ -218,7 +240,9 @@ describe Ohai::System, "Network Plugin" do "prefixlen" => "64", "family" => "inet6" }, - "00:16:3E:2F:36:79" => {"family" => "lladdr"}, + "00:16:3E:2F:36:79" => { + "family" => "lladdr" + }, "192.168.66.33" => { "scope" => "Global", "netmask" => "255.255.255.0", @@ -229,7 +253,8 @@ describe Ohai::System, "Network Plugin" do "3ffe:1111:2222::33" => { "prefixlen" => "48", "family" => "inet6", - "scope" => "Global" + "scope" => "Global", + "state" => "up" } }, "mtu" => "1500", @@ -245,7 +270,9 @@ describe Ohai::System, "Network Plugin" do "prefixlen" => "64", "family" => "inet6" }, - "00:16:3E:2F:36:80" => {"family" => "lladdr"}, + "00:16:3E:2F:36:80" => { + "family" => "lladdr" + }, "192.168.99.11" => { "scope" => "Global", "netmask" => "255.255.255.0", @@ -301,14 +328,14 @@ describe Ohai::System, "Network Plugin" do } } - describe "with linux" do + describe "on linux" do before(:each) do @plugin = get_plugin("network") @plugin["network"] = basic_data["linux"]["network"] end describe "when the linux::network plugin hasn't set any of {ip,ip6,mac}address attributes" do - describe "simple setup" do + describe "simple network setup" do it_populates_ipaddress_attributes it "detects {ip,ip6,mac}address" do @@ -363,10 +390,9 @@ describe Ohai::System, "Network Plugin" do expect(@plugin["ip6address"]).to eq("3ffe:1111:3333::1") end - it "doesn't set macaddress, ipv4 setup is valid and has precedence over ipv6" do - expect(Ohai::Log).not_to receive(:warn).with(/^unable to detect macaddress/) + it "sets macaddress to the ipv6 interface because it hadn't set one for ipv4 first" do @plugin.run - expect(@plugin["macaddress"]).to be_nil + expect(@plugin["macaddress"]).to eq("00:16:3E:2F:36:80") end it "informs about this setup" do @@ -393,10 +419,11 @@ describe Ohai::System, "Network Plugin" do expect(@plugin["macaddress"]).to eq("00:16:3E:2F:36:80") expect(@plugin["ip6address"]).to eq("3ffe:1111:3333::1") end - + it "warns about this conflict" do expect(Ohai::Log).to receive(:debug).with(/^\[inet\] no ipaddress\/mask on eth1/).once expect(Ohai::Log).to receive(:debug).with(/^\[inet6\] no ipaddress\/mask on eth1/).once + allow(Ohai::Log).to receive(:debug) @plugin.run end end @@ -434,9 +461,9 @@ describe Ohai::System, "Network Plugin" do it "warns about this conflict" do expect(Ohai::Log).to receive(:warn).with(/^unable to detect ipaddress/).once - expect(Ohai::Log).to receive(:warn).with(/^unable to detect macaddress/).once expect(Ohai::Log).to receive(:warn).with(/^\[inet\] no ip address on eth0/).once expect(Ohai::Log).to receive(:debug).with(/^unable to detect ip6address/).once + expect(Ohai::Log).to receive(:debug).with(/^unable to detect macaddress/).twice # for each family expect(Ohai::Log).to receive(:warn).with(/^\[inet6\] no ip address on eth0/).once @plugin.run end @@ -465,7 +492,7 @@ describe Ohai::System, "Network Plugin" do it "should warn about it" do expect(Ohai::Log).to receive(:warn).with(/^unable to detect ipaddress/).once - expect(Ohai::Log).to receive(:warn).with(/^unable to detect macaddress/).once + expect(Ohai::Log).to receive(:debug).with(/^unable to detect macaddress/).twice # for each family expect(Ohai::Log).to receive(:debug).with(/^unable to detect ip6address/).once @plugin.run end @@ -769,7 +796,9 @@ describe Ohai::System, "Network Plugin" do it "warns about not being able to set {ip,mac}address (ipv4)" do expect(Ohai::Log).to receive(:warn).with(/^unable to detect ipaddress/).once - expect(Ohai::Log).to receive(:warn).with(/^unable to detect macaddress/).once + expect(Ohai::Log).to receive(:debug).with(/^unable to detect macaddress/) # for ipv4 + expect(Ohai::Log).to receive(:debug).with(/^setting macaddress to/) # for ipv6 + expect(Ohai::Log).to receive(:debug).with(/^\[inet6\] Using default interface eth0 and default gateway/) # for ipv6 @plugin.run end @@ -781,14 +810,46 @@ describe Ohai::System, "Network Plugin" do end it "informs about macaddress being set using the ipv6 setup" do - expect(Ohai::Log).to receive(:debug).with(/^macaddress set to 00:16:3E:2F:36:79 from the ipv6 setup/).once + expect(Ohai::Log).to receive(:debug).with(/^setting macaddress to '00:16:3E:2F:36:79'/) allow(Ohai::Log).to receive(:debug) @plugin.run end end + describe "ipv6 only with ipv4 loopback" do + before do + @plugin["network"]["default_gateway"] = nil + @plugin["network"]["default_interface"] = nil + @plugin["network"]["interfaces"].each do |i,iv| + next if i == 'lo' + iv["addresses"].delete_if{|k,kv| kv["family"] == "inet" } + end + end + + it_doesnt_fail + + it "can't detect ipaddress" do + allow(Ohai::Log).to receive(:warn) + @plugin.run + expect(@plugin["ipaddress"]).to eq("127.0.0.1") + end + + it "sets {ip6,mac}address" do + allow(Ohai::Log).to receive(:warn) + @plugin.run + expect(@plugin["ip6address"]).to eq("3ffe:1111:2222::33") + expect(@plugin["macaddress"]).to eq("00:16:3E:2F:36:79") + end + + it "informs about macaddress being set using the ipv6 setup" do + expect(Ohai::Log).to receive(:debug).with(/^setting macaddress to '00:16:3E:2F:36:79'/) + allow(Ohai::Log).to receive(:debug) + @plugin.run + end + end end + # specs using network plugin data for each mocked OS (freebsd,linux,windows) basic_data.keys.sort.each do |os| describe "the #{os}::network has already set some of the {ip,mac,ip6}address attributes" do before(:each) do @@ -801,13 +862,16 @@ describe Ohai::System, "Network Plugin" do @plugin["macaddress"] = "00:AA:BB:CC:DD:EE" @expected_results = { "freebsd" => { - "ip6address" => "::1" + "ip6address" => "2001:470:d:cb4::1", + "macaddress" => "02:20:6f:d2:c4:00" }, "linux" => { - "ip6address" => "3ffe:1111:2222::33" + "ip6address" => "3ffe:1111:2222::33", + "macaddress" => "00:16:3E:2F:36:79" }, "windows" => { - "ip6address" => "fe80::698d:3e37:7950:b28c" + "ip6address" => "fe80::698d:3e37:7950:b28c", + "macaddress" => "00:AA:BB:CC:DD:EE" } } end @@ -870,6 +934,17 @@ describe Ohai::System, "Network Plugin" do end end @plugin["ip6address"] = "3ffe:8888:9999::1" + @expected_results = { + "freebsd" => { + "macaddress" => "02:20:6f:d2:c4:00" + }, + "linux" => { + "macaddress" => "00:16:3E:2F:36:79" + }, + "windows" => { + "macaddress" => "52:54:44:66:66:02" + } + } end it_doesnt_fail @@ -880,15 +955,14 @@ describe Ohai::System, "Network Plugin" do expect(@plugin["ipaddress"]).to be_nil end - it "can't detect macaddress either" do + it "takes the macaddress from ipv6" do allow(Ohai::Log).to receive(:warn) @plugin.run - expect(@plugin["macaddress"]).to be_nil + expect(@plugin["macaddress"]).to eq(@expected_results[os]["macaddress"]) end - it "warns about not being able to set {ip,mac}address" do + it "warns about not being able to set ipaddress" do expect(Ohai::Log).to receive(:warn).with(/^unable to detect ipaddress/).once - expect(Ohai::Log).to receive(:warn).with(/^unable to detect macaddress/).once @plugin.run end @@ -923,10 +997,10 @@ describe Ohai::System, "Network Plugin" do it_populates_ipaddress_attributes - it "detects ipaddress and overwrite macaddress" do + it "detects ipaddress and does not overwrite macaddress" do @plugin.run expect(@plugin["ipaddress"]).to eq(@expected_results[os]["ipaddress"]) - expect(@plugin["macaddress"]).to eq(@expected_results[os]["macaddress"]) + expect(@plugin["macaddress"]).to eq(@plugin["macaddress"]) end it "doesn't overwrite ip6address" do @@ -990,10 +1064,9 @@ describe Ohai::System, "Network Plugin" do it_doesnt_fail - it "doesn't overwrite {ip,mac,ip6}address" do + it "doesn't overwrite {ip,ip6}address" do @plugin.run expect(@plugin["ipaddress"]).to eq("10.11.12.13") - expect(@plugin["macaddress"]).to eq(nil) expect(@plugin["ip6address"]).to eq("3ffe:8888:9999::1") end end |