Prevent a bond for unrequired re-assembles

* Assemble bond members under bond in UP state
* FIX lost bridge parameter
* FIX lost 'use_carrier' bond property
* waiting for bond UP after slaves added
* additional flush IP addresses from slave while bond assemble

Change-Id: I568d852e65dc5d5c246e11deb0740f4a608f5ecc
Closes-bug: #1658981
Related-bug: #1657750
(cherry picked from commit 6fde41c44a)
This commit is contained in:
Sergey Vasilenko 2017-01-30 17:53:13 +03:00
parent af4d0aa90f
commit a848384706
5 changed files with 65 additions and 86 deletions

View File

@ -520,6 +520,11 @@ class Puppet::Provider::L2_base < Puppet::Provider::InterfaceToolset
bond[bond_name][:bond_properties][:ad_select] = ad_select
end
bond[bond_name][:onboot] = !self.get_iface_state(bond_name).nil?
bond[bond_name][:bond_properties][:use_carrier] = self.get_sys_class("/sys/class/net/#{bond_name}/bonding/use_carrier")
# get bridge, if bond a member an one
if self.get_port_bridges_pairs[bond_name]
bond[bond_name][:bridge] = self.get_port_bridges_pairs[bond_name][:bridge]
end
end
debug("get_lnx_bonds: LNX bond list #{bond}")
return bond

View File

@ -29,21 +29,6 @@ Puppet::Type.type(:l2_bond).provide(:lnx, :parent => Puppet::Provider::Lnx_base)
:vendor_specific => {}
}
props.merge! bond_props
# # get bridge if port included to it
# if ! port_bridges_hash[if_name].nil?
# props[:bridge] = port_bridges_hash[if_name][:bridge]
# end
# # calculate port_type field
# if !bridges[if_name].nil?
# case bridges[if_name][:br_type]
# when :ovs
# props[:port_type] = 'ovs:br:unremovable'
# when :lnx
# props[:port_type] = 'lnx:br:unremovable'
# else
# # pass
# end
# end
debug("PREFETCHED properties for '#{bond_name}': #{props}")
rv << new(props)
end
@ -66,34 +51,9 @@ Puppet::Type.type(:l2_bond).provide(:lnx, :parent => Puppet::Provider::Lnx_base)
if ! @property_flush.empty?
debug("FLUSH properties: #{@property_flush}")
bond_prop_dir = "/sys/class/net/#{@resource[:bond]}"
runtime_slave_ports = self.class.get_sys_class("#{bond_prop_dir}/bonding/slaves", true)
bond_is_up = !self.class.get_iface_state(@resource[:bond]).nil?
# FLUSH changed properties
if @property_flush.has_key? :slaves
runtime_slave_ports = self.class.get_sys_class("/sys/class/net/#{@resource[:bond]}/bonding/slaves", true)
if @property_flush[:slaves].nil? or @property_flush[:slaves] == :absent
debug("Remove all slave ports from bond '#{@resource[:bond]}'")
rm_slave_list = runtime_slave_ports
else
rm_slave_list = runtime_slave_ports - @property_flush[:slaves]
if !rm_slave_list.empty?
debug("Remove '#{rm_slave_list.join(',')}' ports from bond '#{@resource[:bond]}'")
rm_slave_list.each do |slave|
self.class.interface_down(slave) # need by kernel requirements by design. undocumented :(
self.class.set_sys_class("#{bond_prop_dir}/bonding/slaves", "-#{slave}")
end
end
# add interfaces to bond
add_slave_list = @property_flush[:slaves] - runtime_slave_ports
if !add_slave_list.empty?
debug("Add '#{add_slave_list.join(',')}' ports to bond '#{@resource[:bond]}'")
add_slave_list.each do |slave|
debug("Add interface '#{slave}' to bond '#{@resource[:bond]}'")
self.class.interface_down(slave) # need by kernel requirements by design. undocumented :(
self.class.set_sys_class("#{bond_prop_dir}/bonding/slaves", "+#{slave}")
self.class.interface_up(slave)
end
end
end
end
if @property_flush.has_key? :bond_properties
bond_properties_to_change = @property_flush[:bond_properties]
if @old_property_hash[:bond_properties] and !@old_property_hash[:bond_properties].empty?
@ -101,14 +61,11 @@ Puppet::Type.type(:l2_bond).provide(:lnx, :parent => Puppet::Provider::Lnx_base)
bond_properties_to_change = Hash[*bond_properties_to_change.flatten]
end
debug("Bond properties which are going to be changed #{bond_properties_to_change}")
# change bond_properties
bond_is_up = !self.class.get_iface_state(@resource[:bond]).nil?
# Reassemble bond if we change bond mode
need_reassembling = true if bond_properties_to_change[:mode] and self.class.get_sys_class("#{bond_prop_dir}/bonding/#{'mode'}") != bond_properties_to_change[:mode]
if need_reassembling
if need_reassembling and !runtime_slave_ports.empty?
self.class.interface_down(@resource[:bond])
bond_is_up = false
runtime_slave_ports = self.class.get_sys_class("#{bond_prop_dir}/bonding/slaves", true)
debug("Disassemble bond '#{@resource[:bond]}'")
runtime_slave_ports.each do |eth|
debug("Remove interface '#{eth}' from bond '#{@resource[:bond]}'")
@ -163,16 +120,63 @@ Puppet::Type.type(:l2_bond).provide(:lnx, :parent => Puppet::Provider::Lnx_base)
debug("Unsupported property '#{prop}' for bond '#{@resource[:bond]}'")
end
end
if need_reassembling
if need_reassembling and !runtime_slave_ports.empty?
# re-assemble bond after configuration
debug("Re-assemble bond '#{@resource[:bond]}'")
self.class.interface_up(@resource[:bond])
runtime_slave_ports.each do |eth|
debug("Add interface '#{eth}' to bond '#{@resource[:bond]}'")
self.class.set_sys_class("#{bond_prop_dir}/bonding/slaves", "+#{eth}")
end
end
self.class.interface_up(@resource[:bond]) if !bond_is_up
end
# set interface state to UP
if !bond_is_up
self.class.interface_up(@resource[:bond])
bond_is_up = true
end
# Change list of slaves
if @property_flush.has_key? :slaves
if @property_flush[:slaves].nil? or @property_flush[:slaves] == :absent
debug("Remove all slave ports from bond '#{@resource[:bond]}'")
rm_slave_list = runtime_slave_ports
else
rm_slave_list = runtime_slave_ports - @property_flush[:slaves]
if !rm_slave_list.empty?
debug("Remove '#{rm_slave_list.join(',')}' ports from bond '#{@resource[:bond]}'")
rm_slave_list.each do |slave|
self.class.interface_down(slave) # need by kernel requirements by design. undocumented :(
self.class.set_sys_class("#{bond_prop_dir}/bonding/slaves", "-#{slave}")
end
end
# add interfaces to bond
add_slave_list = @property_flush[:slaves] - runtime_slave_ports
if !add_slave_list.empty?
debug("Add '#{add_slave_list.join(',')}' ports to bond '#{@resource[:bond]}'")
add_slave_list.each do |slave|
debug("Add interface '#{slave}' to bond '#{@resource[:bond]}'")
self.class.interface_down(slave) # need by kernel requirements by design. undocumented :(
self.class.iproute("addr flush dev #{slave}")
self.class.set_sys_class("#{bond_prop_dir}/bonding/slaves", "+#{slave}")
self.class.interface_up(slave)
end
end
end
if bond_is_up
# waiting for bond became UP
wait_time = @resource[:bond_properties][:updelay].to_i/1000 || 60.0
wait_step = 0.5
while !self.class.get_iface_state(@resource[:bond]) and wait_time>0 do
debug("Waiting for bond '#{@resource[:bond]}' interface UP (#{wait_time})")
sleep(wait_step)
wait_time -= wait_step
end
end
end
# Make bond a member of bridge
if @property_flush.has_key? :bridge
# get actual bridge-list. We should do it here,
# because bridge may be not existing at prefetch stage.
@ -182,14 +186,9 @@ Puppet::Type.type(:l2_bond).provide(:lnx, :parent => Puppet::Provider::Lnx_base)
debug("Actual-port-bridge-mapping: '#{port_bridges_hash}'") # it should removed from LNX
#
# remove interface from old bridge
bond_is_up = !self.class.get_iface_state(@resource[:bond]).nil?
if ! port_bridges_hash[@resource[:bond]].nil?
br_name = port_bridges_hash[@resource[:bond]][:bridge]
if br_name != @resource[:bond]
if bond_is_up
self.class.interface_down(@resource[:bond], true)
bond_is_up = false
end
# do not remove bridge-based interface from his bridge
case port_bridges_hash[@resource[:bond]][:br_type]
when :ovs
@ -214,7 +213,6 @@ Puppet::Type.type(:l2_bond).provide(:lnx, :parent => Puppet::Provider::Lnx_base)
#pass
end
end
self.class.interface_up(@resource[:bond]) if !bond_is_up
debug("Change bridge")
end
if @property_flush[:onboot]

View File

@ -71,36 +71,6 @@ Puppet::Type.type(:l2_port).provide(:lnx, :parent => Puppet::Provider::Lnx_base)
end
#
# FLUSH changed properties
if @property_flush.has_key? :bond_master and @property_flush[:bond_master] != :absent
bond = @old_property_hash[:bond_master]
if self.class.ipaddr_exist? @resource[:interface]
# remove all IP addresses from member of bond. This should be done on device in UP state
self.class.addr_flush(@resource[:interface])
end
# putting interface to the down-state, because add/remove upped interface impossible. undocumented kern.behavior.
self.class.interface_down(@resource[:interface], true)
if bond and bond != :absent and File.exist?("/sys/class/net/#{@resource[:interface]}/master/bonding/slaves")
# remove interface from bond, if one included to it
debug("Remove interface '#{@resource[:interface]}' from bond '#{bond}'.")
File.open("/sys/class/net/#{@resource[:interface]}/master/bonding/slaves", "a") {|f| f << "-#{@resource[:interface]}"}
end
if ! @property_flush[:bond_master].nil? and @property_flush[:bond_master] != :absent
# add interface as slave to bond
if File.exist? "/sys/class/net/#{@property_flush[:bond_master]}/bonding/slaves"
# If port is bond member and bond still doesn't exist we skip the adding to bond action
# Bond will do it by itself during bond creation
debug("Add interface '#{@resource[:interface]}' to bond '#{@property_flush[:bond_master]}'.")
File.open("/sys/class/net/#{@property_flush[:bond_master]}/bonding/slaves", "a") {|f| f << "+#{@resource[:interface]}"}
end
else
# port no more member of any bonds
@property_flush[:port_type] = nil
end
# Up parent interface if this is vlan port
self.class.interface_up(@resource[:vlan_dev]) if @resource[:vlan_dev]
# Up port
self.class.interface_up(@resource[:interface])
end
if @property_flush.has_key? :bridge
# get actual bridge-list. We should do it here,
# because bridge may be not existing at prefetch stage.

View File

@ -267,7 +267,8 @@ type : patch
:mode=>"balance-rr",
:miimon=>"0",
:updelay=>"0",
:downdelay=>"0"
:downdelay=>"0",
:use_carrier=>"1"
},
:onboot=>false
}
@ -296,6 +297,7 @@ type : patch
end
it 'parses the sysfs to get_lnx_bonds' do
subject.stubs(:ovs_vsctl).with('list-br').returns({})
subject.stubs(:get_sys_class).with('/sys/class/net/bonding_masters', true).returns(['bond0'])
subject.stubs(:get_sys_class).with('/sys/class/net/bond0/bonding/mode').returns('balance-rr')
subject.stubs(:get_sys_class).with('/sys/class/net/bond0/mtu').returns('1500')
@ -304,7 +306,7 @@ type : patch
subject.stubs(:get_sys_class).with('/sys/class/net/bond0/bonding/updelay').returns('0')
subject.stubs(:get_sys_class).with('/sys/class/net/bond0/bonding/downdelay').returns('0')
subject.stubs(:get_sys_class).with('/sys/class/net/bond0/bonding/mode').returns('balance-rr')
subject.stubs(:get_sys_class).with('/sys/class/net/bond0/bonding/mode').returns('balance-rr')
subject.stubs(:get_sys_class).with('/sys/class/net/bond0/bonding/use_carrier').returns('1')
expect(subject.get_lnx_bonds).to eq get_lnx_bonds_result
end

View File

@ -55,6 +55,8 @@ describe Puppet::Type.type(:l2_bond).provider(:lnx) do
provider.class.stubs(:set_sys_class).with('/sys/class/net/bond1/bonding/updelay', '111').returns(true)
provider.class.stubs(:get_sys_class).with('/sys/class/net/bond1/bonding/downdelay').returns('0')
provider.class.stubs(:set_sys_class).with('/sys/class/net/bond1/bonding/downdelay', '222').returns(true)
provider.class.stubs(:iproute).with('addr flush dev eth1').returns(true)
provider.class.stubs(:iproute).with('addr flush dev eth2').returns(true)
provider.class.stubs(:interface_up).with('bond1').returns(true)
provider.class.stubs(:interface_up).with('eth1').returns(true)
provider.class.stubs(:interface_up).with('eth2').returns(true)
@ -239,6 +241,8 @@ describe Puppet::Type.type(:l2_bond).provider(:lnx) do
provider.class.stubs(:get_bridge_list).returns({'br-ovs'=>{:br_type=>:ovs},})
provider.class.stubs(:get_port_bridges_pairs).returns({"br-storage"=>{:bridge=>"br-storage", :br_type=>:ovs}})
provider.class.stubs(:ovs_vsctl).with(['add-port', 'br-ovs', 'bond12']).once
provider.class.stubs(:iproute).with('addr flush dev eth1').returns(true)
provider.class.stubs(:iproute).with('addr flush dev eth2').returns(true)
provider.class.stubs(:interface_up).with('bond12').returns(true)
provider.class.stubs(:interface_up).with('eth1').returns(true)
provider.class.stubs(:interface_up).with('eth2').returns(true)