diff options
author | Laurent <laurent+chef@u-picardie.fr> | 2012-04-05 03:00:46 +0200 |
---|---|---|
committer | Bryan McLellan <btm@opscode.com> | 2012-06-08 08:42:51 -0700 |
commit | 7fbb125ee624aa839bb76979c4c49aac6e884346 (patch) | |
tree | 83c7ab41f77cda06a5f103a1f14c465e3b1c0419 | |
parent | 256ba7db6227d70dc3eb97f0feb09e2133320789 (diff) | |
download | ohai-7fbb125ee624aa839bb76979c4c49aac6e884346.tar.gz |
OHAI-355 WIP, new algorithm to set ipaddress (v4 & v6}
TODO:
- more tests
- handling of point to point interfaces
-rw-r--r-- | lib/ohai/plugins/network.rb | 81 | ||||
-rw-r--r-- | spec/ohai/plugins/network_spec.rb | 96 |
2 files changed, 147 insertions, 30 deletions
diff --git a/lib/ohai/plugins/network.rb b/lib/ohai/plugins/network.rb index 3087f293..33559d0e 100644 --- a/lib/ohai/plugins/network.rb +++ b/lib/ohai/plugins/network.rb @@ -25,31 +25,55 @@ network[:interfaces] = Mash.new unless network[:interfaces] counters Mash.new unless counters counters[:network] = Mash.new unless counters[:network] -ipaddress nil -ip6address -macaddress nil - require_plugin "hostname" require_plugin "#{os}::network" # ipaddress and macaddress can be set from the #{os}::network plugin return unless ipaddress.nil? -def find_ip_and_mac(addresses, match = nil) - ip = nil; mac = nil; ip6 = nil - addresses.keys.each do |addr| - if match.nil? - ip = addr if addresses[addr]["family"].eql?("inet") - else - ip = addr if addresses[addr]["family"].eql?("inet") && network_contains_address(match, addr, addresses[addr]) +def find_ip_and_iface(family = "inet", match = nil) + raise "bad family #{family}" unless [ "inet", "inet6" ].include? family + + # going to use that later to sort by scope + scope_prio = [ "global", "site", "link", "host", "node", nil ] + + ipaddresses = [] + # trying to write it as readable as possible (iow it's not a kick-ass optimised one-liner) + # ipaddresses going to hold #{family} ipaddresses and their scope + Mash[network['interfaces']].each do |iface, iface_v| + 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 << { + :ipaddress => IPAddress("#{addr}/#{addr_v["prefixlen"]}"), + :scope => addr_v["scope"], + :iface => iface + } end - ip6 = addr if addresses[addr]["family"].eql?("inet6") && addresses[addr]["scope"].eql?("Global") - mac = addr if addresses[addr]["family"].eql?("lladdr") - break if (ip and mac) end - Ohai::Log.debug("Found IPv4 address #{ip} with MAC #{mac} #{match.nil? ? '' : 'matching address ' + match}") - Ohai::Log.debug("Found IPv6 address #{ip6}") if ip6 - [ip, mac, ip6] + + if match.nil? + # sort ip addresses by scope, by prefixlen and then by ip address + # then return the first ip address + r = ipaddresses.sort_by! do |v| + [ ( scope_prio.index(v[:scope].downcase) or 999999 ), + v[:ipaddress].prefix, + ( family == "inet" ? v[:ipaddress].to_u32 : v[:ipaddress].to_u128 ) + ] + end.first + else + # sort by prefixlen + # return the first matching ip address + r = ipaddresses.sort do |a,b| + a[:ipaddress].prefix <=> b[:ipaddress].prefix + end.select do |v| + v[:ipaddress].include? IPAddress(match) + end.first + end + [ r[:ipaddress].to_s, r[:iface] ] +end + +def find_mac_from_iface(iface) + network["interfaces"][iface]["addresses"].select{|k,v| v["family"]=="lladdr"}.first.first end def network_contains_address(address_to_match, network_ip, network_opts) @@ -64,24 +88,21 @@ end # If we have a default interface that has addresses, populate the short-cut attributes # 0.0.0.0 is not a valid gateway address in this case +iface=nil if network[:default_interface] and network[:default_gateway] and network[:default_gateway] != "0.0.0.0" and network["interfaces"][network[:default_interface]] and network["interfaces"][network[:default_interface]]["addresses"] Ohai::Log.debug("Using default interface for default ip and mac address") - im = find_ip_and_mac(network["interfaces"][network[:default_interface]]["addresses"], network[:default_gateway]) - ipaddress im.shift - macaddress im.shift - ip6address im.shift + ( ip, iface ) = find_ip_and_iface("inet", network[:default_gateway]) + raise "something wrong happened #{network[:default_interface]} != #{iface}" if network[:default_interface] != iface + ipaddress ip else - network["interfaces"].keys.sort.each do |iface| - if network["interfaces"][iface]["encapsulation"].eql?("Ethernet") - Ohai::Log.debug("Picking ip and mac address from first Ethernet interface") - im = find_ip_and_mac(network["interfaces"][iface]["addresses"]) - ipaddress im.shift - macaddress im.shift - return if (ipaddress and macaddress) - end - end + ( ip, iface ) = find_ip_and_iface("inet") + ipaddress ip end +macaddress find_mac_from_iface(iface) +( ip6, iface6 ) = find_ip_and_iface("inet6") +ip6address ip6 +Ohai::Log.warn("ipaddress and ip6address are set from different interfaces (#{iface} & #{iface6}), macaddress has been set using the ipaddress interface") if iface != iface6 diff --git a/spec/ohai/plugins/network_spec.rb b/spec/ohai/plugins/network_spec.rb new file mode 100644 index 00000000..9044d96a --- /dev/null +++ b/spec/ohai/plugins/network_spec.rb @@ -0,0 +1,96 @@ +# +# Author:: Laurent Desarmes <laurent.desarmes@u-picardie.fr> +# Copyright:: Copyright (c) 2012 Laurent Desarmes +# 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. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper.rb') + +describe Ohai::System, "Network Plugin" do + + checks = { + "linux" => { + "data" => { + # pp Hash[node['network']] from shef to get the network data + # have just removed the arp entries by hand + "network" => {"default_interface"=>"eth0", + "interfaces"=> + {"lo"=> + {"flags"=>["LOOPBACK", "UP"], + "addresses"=> + {"::1"=>{"scope"=>"Node", "prefixlen"=>"128", "family"=>"inet6"}, + "127.0.0.1"=> + {"scope"=>"Node", + "netmask"=>"255.0.0.0", + "prefixlen"=>"8", + "family"=>"inet"}}, + "mtu"=>"16436", + "encapsulation"=>"Loopback"}, + "eth0"=> + {"flags"=>["BROADCAST", "MULTICAST", "UP"], + "number"=>"0", + "addresses"=> + {"fe80::216:3eff:fe2f:3679"=> + {"scope"=>"Link", "prefixlen"=>"64", "family"=>"inet6"}, + "00:16:3E:2F:36:79"=>{"family"=>"lladdr"}, + "192.168.66.33"=> + {"scope"=>"Global", + "netmask"=>"255.255.255.0", + "broadcast"=>"192.168.66.255", + "prefixlen"=>"24", + "family"=>"inet"}}, + "routes"=>{"192.168.66.0/24"=>{"scope"=>"Link", "src"=>"192.168.66.33"}}, + "mtu"=>"1500", + "type"=>"eth", + "encapsulation"=>"Ethernet"}}, + "default_gateway"=>"192.168.66.15"} + }, + "expected_results" => { + "ipaddress" => "192.168.66.33", + "macaddress" => "00:16:3E:2F:36:79" + } + }, + "linux with {ip,mac}address set from the linux plugin" => { + "data" => { + "ipaddress" => "192.168.66.33", + "macaddress" => "00:16:3E:2F:36:79" + }, + "expected_results" => { + "ipaddress" => "192.168.66.33", + "macaddress" => "00:16:3E:2F:36:79" + } + } + } + + checks.each do | check_name, check_data | + describe "it checks results from #{check_name}" do + before do + @ohai = Ohai::System.new + @ohai.stub!(:require_plugin).and_return(true) + check_data["data"].keys.each do |k| + @ohai[k] = check_data["data"][k] + end + end + + check_data["expected_results"].each do |attribute, value| + it "sets #{attribute}" do + @ohai._require_plugin("network") + @ohai.should have_key(attribute) + @ohai[attribute].should == value! + end + end + end + end +end |