summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Smith <tsmith@chef.io>2015-12-14 11:25:33 -0800
committerTim Smith <tsmith@chef.io>2015-12-14 11:25:33 -0800
commit975d8e7186484a4208034fef5ad42b8ae22d3fac (patch)
tree3f82f26e68840b87c4120c1ce2d3522e8191e537
parentde20410be19e8b88a17d0a4a27b9e5c16875baeb (diff)
parentc2051dcb50872462ca3df19f13ca9cd513ccc18c (diff)
downloadohai-975d8e7186484a4208034fef5ad42b8ae22d3fac.tar.gz
Merge pull request #680 from phreakocious/master
Add support for collecting ethernet layer one information from ethtool on linux
-rw-r--r--lib/ohai/plugins/linux/network.rb28
-rw-r--r--spec/unit/plugins/linux/network_spec.rb48
2 files changed, 76 insertions, 0 deletions
diff --git a/lib/ohai/plugins/linux/network.rb b/lib/ohai/plugins/linux/network.rb
index 51eff9dd..689001dc 100644
--- a/lib/ohai/plugins/linux/network.rb
+++ b/lib/ohai/plugins/linux/network.rb
@@ -41,6 +41,10 @@ Ohai.plugin(:Network) do
["/sbin/ip", "/usr/bin/ip", "/bin/ip"].any? { |path| File.exist?(path) }
end
+ def find_ethtool_binary
+ ["/sbin/ethtool", "/usr/sbin/ethtool"].find { |path| File.exist?(path) }
+ end
+
def is_openvz?
::File.directory?('/proc/vz')
end
@@ -134,6 +138,28 @@ Ohai.plugin(:Network) do
end.compact.flatten
end
+ def ethernet_layer_one(iface)
+ return iface unless ethtool_binary = find_ethtool_binary
+ keys = %w[ Speed Duplex Port Transceiver Auto-negotiation MDI-X ]
+ iface.each_key do |tmp_int|
+ next unless iface[tmp_int][:encapsulation] == 'Ethernet'
+ so = shell_out("#{ethtool_binary} #{tmp_int}")
+ so.stdout.lines do |line|
+ line.chomp!
+ Ohai::Log.debug("Parsing ethtool output: #{line}")
+ line.lstrip!
+ k, v = line.split(': ')
+ next unless keys.include? k
+ k.downcase!.tr!('-', '_')
+ if k == 'speed'
+ k = 'link_speed' # This is not necessarily the maximum speed the NIC supports
+ v = v[/\d+/].to_i
+ end
+ iface[tmp_int][k] = v
+ end
+ end
+ iface
+ end
def link_statistics(iface, net_counters)
so = shell_out("ip -d -s link")
@@ -477,6 +503,8 @@ Ohai.plugin(:Network) do
end
end
end
+
+ iface = ethernet_layer_one(iface)
counters[:network][:interfaces] = net_counters
network["interfaces"] = iface
end
diff --git a/spec/unit/plugins/linux/network_spec.rb b/spec/unit/plugins/linux/network_spec.rb
index 7b5dcbde..de5a89ce 100644
--- a/spec/unit/plugins/linux/network_spec.rb
+++ b/spec/unit/plugins/linux/network_spec.rb
@@ -298,6 +298,31 @@ fe80::21c:eff:fe12:3456 dev eth0.153 lladdr 00:1c:0e:30:28:00 router REACHABLE
'
}
+ let(:linux_ethtool) {
+'Settings for eth0:
+ Supported ports: [ FIBRE ]
+ Supported link modes: 1000baseT/Full
+ 10000baseT/Full
+ Supported pause frame use: No
+ Supports auto-negotiation: Yes
+ Advertised link modes: 1000baseT/Full
+ 10000baseT/Full
+ Advertised pause frame use: No
+ Advertised auto-negotiation: Yes
+ Speed: 10000Mb/s
+ Duplex: Full
+ Port: FIBRE
+ PHYAD: 0
+ Transceiver: external
+ Auto-negotiation: on
+ Supports Wake-on: d
+ Wake-on: d
+ Current message level: 0x00000007 (7)
+ drv probe link
+ Link detected: yes
+'
+ }
+
before(:each) do
allow(plugin).to receive(:collect_os).and_return(:linux)
@@ -311,6 +336,7 @@ fe80::21c:eff:fe12:3456 dev eth0.153 lladdr 00:1c:0e:30:28:00 router REACHABLE
allow(plugin).to receive(:shell_out).with("route -n").and_return(mock_shell_out(0, linux_route_n, ""))
allow(plugin).to receive(:shell_out).with("ifconfig -a").and_return(mock_shell_out(0, linux_ifconfig, ""))
allow(plugin).to receive(:shell_out).with("arp -an").and_return(mock_shell_out(0, linux_arp_an, ""))
+ allow(plugin).to receive(:shell_out).with(/ethtool/).and_return(mock_shell_out(0, linux_ethtool, ""))
end
describe "#iproute2_binary_available?" do
@@ -323,11 +349,23 @@ fe80::21c:eff:fe12:3456 dev eth0.153 lladdr 00:1c:0e:30:28:00 router REACHABLE
end
end
+ describe "#find_ethtool_binary" do
+ ["/sbin/ethtool", "/usr/sbin/ethtool"].each do |path|
+ it "accepts #{path}" do
+ allow(File).to receive(:exist?).and_return(false)
+ allow(File).to receive(:exist?).with(path).and_return(true)
+ expect(plugin.find_ethtool_binary).to end_with("/ethtool")
+ end
+ end
+ end
+
+
["ifconfig","iproute2"].each do |network_method|
describe "gathering IP layer address info via #{network_method}" do
before(:each) do
allow(plugin).to receive(:iproute2_binary_available?).and_return( network_method == "iproute2" )
+ allow(plugin).to receive(:find_ethtool_binary).and_return( '/sbin/ethtool' )
plugin.run
end
@@ -340,6 +378,15 @@ fe80::21c:eff:fe12:3456 dev eth0.153 lladdr 00:1c:0e:30:28:00 router REACHABLE
expect(plugin['network']['interfaces'].keys.sort).to eq(["eth0", "eth0.11", "eth0.151", "eth0.152", "eth0.153", "eth0:5", "eth3", "foo:veth0@eth0", "lo", "ovs-system", "tun0", "venet0", "venet0:0", "xapi1"])
end
+ it "detects the layer one details of an ethernet interface" do
+ expect(plugin['network']['interfaces']['eth0']['link_speed']).to eq(10000)
+ expect(plugin['network']['interfaces']['eth0']['duplex']).to eq('Full')
+ expect(plugin['network']['interfaces']['eth0']['port']).to eq('FIBRE')
+ expect(plugin['network']['interfaces']['eth0']['transceiver']).to eq('external')
+ expect(plugin['network']['interfaces']['eth0']['auto_negotiation']).to eq('on')
+ expect(plugin['network']['interfaces']['eth0']['mdi_x']).to be_nil
+ end
+
it "detects the ipv4 addresses of the ethernet interface" do
expect(plugin['network']['interfaces']['eth0']['addresses'].keys).to include('10.116.201.76')
expect(plugin['network']['interfaces']['eth0']['addresses']['10.116.201.76']['netmask']).to eq('255.255.255.0')
@@ -547,6 +594,7 @@ Destination Gateway Genmask Flags Metric Ref Use Iface
before(:each) do
allow(File).to receive(:exist?).with("/sbin/ip").and_return(true) # iproute2 only
allow(File).to receive(:exist?).with("/proc/net/if_inet6").and_return(true) # ipv6 is enabled
+ allow(File).to receive(:exist?).with("/sbin/ethtool").and_return(true) # ethtool is available
plugin.run
end