diff --git a/deployment/puppet/l23network/lib/puppet/provider/interface_toolset.rb b/deployment/puppet/l23network/lib/puppet/provider/interface_toolset.rb index c6f3a45cfc..eaa432f404 100644 --- a/deployment/puppet/l23network/lib/puppet/provider/interface_toolset.rb +++ b/deployment/puppet/l23network/lib/puppet/provider/interface_toolset.rb @@ -85,6 +85,7 @@ class Puppet::Provider::InterfaceToolset < Puppet::Provider end def self.interface_up(iface, force=false) + debug("Setting #{iface} up") cmd = ['link', 'set', 'up', 'dev', iface] cmd.insert(0, '--force') if force begin @@ -98,6 +99,7 @@ class Puppet::Provider::InterfaceToolset < Puppet::Provider end def self.interface_down(iface, force=false) + debug("Setting #{iface} down") cmd = ['link', 'set', 'down', 'dev', iface] cmd.insert(0, '--force') if force begin @@ -226,4 +228,4 @@ class Puppet::Provider::InterfaceToolset < Puppet::Provider end -# vim: set ts=2 sw=2 et : \ No newline at end of file +# vim: set ts=2 sw=2 et : diff --git a/deployment/puppet/l23network/lib/puppet/provider/l2_bond/lnx.rb b/deployment/puppet/l23network/lib/puppet/provider/l2_bond/lnx.rb index 8e3d598236..32c21a7e38 100644 --- a/deployment/puppet/l23network/lib/puppet/provider/l2_bond/lnx.rb +++ b/deployment/puppet/l23network/lib/puppet/provider/l2_bond/lnx.rb @@ -98,19 +98,21 @@ Puppet::Type.type(:l2_bond).provide(:lnx, :parent => Puppet::Provider::Lnx_base) end if @property_flush.has_key? :bond_properties # change bond_properties - need_reassemble = [:mode, :lacp_rate] - #todo(sv): inplement re-assembling only if it need - #todo(sv): re-set only delta between reality and requested - runtime_bond_state = !self.class.get_iface_state(@resource[:bond]).nil? - 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]}'") - # for most bond options we should disassemble bond before re-configuration. In the kernel module documentation - # says, that bond interface should be downed, but it's not enouth. - self.class.set_sys_class("#{bond_prop_dir}/bonding/slaves", "-#{eth}") + bond_is_up = !self.class.get_iface_state(@resource[:bond]).nil? + # Reassemble bond if we change bond mode + need_reassembling = true if self.class.get_sys_class("#{bond_prop_dir}/bonding/#{'mode'}") != @property_flush[:bond_properties][:mode] + if need_reassembling + 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]}'") + # for most bond options we should disassemble bond before re-configuration. In the kernel module documentation + # says, that bond interface should be downed, but it's not enouth. + self.class.set_sys_class("#{bond_prop_dir}/bonding/slaves", "-#{eth}") + end end - self.class.interface_down(@resource[:bond]) # setup primary bond_properties primary_bond_properties = [:mode, :xmit_hash_policy] debug("Set primary bond properties [#{primary_bond_properties.join(',')}] for bond '#{@resource[:bond]}'") @@ -122,7 +124,11 @@ Puppet::Type.type(:l2_bond).provide(:lnx, :parent => Puppet::Provider::Lnx_base) if ['', 'nil', 'undef'].include? should_pprop debug("Skip undefined property '#{pprop}'='#{should_pprop}' for bond '#{@resource[:bond]}'") elsif curr_pprop != should_pprop - debug("Setting #{pprop} '#{should_pprop}' for bond '#{@resource[:bond]}'") + if bond_is_up + self.class.interface_down(@resource[:bond]) + bond_is_up = false + end + debug("Setting #{pprop} '#/{should_pprop}' for bond '#{@resource[:bond]}'") self.class.set_sys_class("#{bond_prop_dir}/bonding/#{pprop}", should_pprop) sleep(1) else @@ -140,6 +146,10 @@ Puppet::Type.type(:l2_bond).provide(:lnx, :parent => Puppet::Provider::Lnx_base) val_should_be = val.to_s val_actual = self.class.get_sys_class("#{bond_prop_dir}/bonding/#{prop}") if val_actual != val_should_be + if bond_is_up + self.class.interface_down(@resource[:bond]) + bond_is_up = false + end debug("Setting property '#{prop}' to '#{val_should_be}' for bond '#{@resource[:bond]}'") self.class.set_sys_class("#{bond_prop_dir}/bonding/#{prop}", val_should_be) else @@ -149,13 +159,15 @@ Puppet::Type.type(:l2_bond).provide(:lnx, :parent => Puppet::Provider::Lnx_base) debug("Unsupported property '#{prop}' for bond '#{@resource[:bond]}'") end end - # re-assemble bond after configuration - self.class.interface_up(@resource[:bond]) if runtime_bond_state - debug("Re-assemble bond '#{@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}") + if need_reassembling + # re-assemble bond after configuration + debug("Re-assemble bond '#{@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 if @property_flush.has_key? :bridge # get actual bridge-list. We should do it here, @@ -166,11 +178,14 @@ 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 - runtime_bond_state = !self.class.get_iface_state(@resource[:bond]).nil? - self.class.interface_down(@resource[:bond], true) + 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 @@ -195,11 +210,11 @@ Puppet::Type.type(:l2_bond).provide(:lnx, :parent => Puppet::Provider::Lnx_base) #pass end end - self.class.interface_up(@resource[:bond]) if runtime_bond_state + self.class.interface_up(@resource[:bond]) if !bond_is_up debug("Change bridge") end if @property_flush[:onboot] - self.class.interface_up(@resource[:bond]) + self.class.interface_up(@resource[:bond]) if self.class.get_iface_state(@resource[:bond]).nil? end if !['', 'absent'].include? @property_flush[:mtu].to_s self.class.set_mtu(@resource[:bond], @property_flush[:mtu]) diff --git a/deployment/puppet/l23network/spec/unit/puppet/provider/l2_bond/lnx_bond__spec.rb b/deployment/puppet/l23network/spec/unit/puppet/provider/l2_bond/lnx_bond__spec.rb index fdcdefdebe..9e49ff0f4f 100644 --- a/deployment/puppet/l23network/spec/unit/puppet/provider/l2_bond/lnx_bond__spec.rb +++ b/deployment/puppet/l23network/spec/unit/puppet/provider/l2_bond/lnx_bond__spec.rb @@ -29,6 +29,7 @@ describe Puppet::Type.type(:l2_bond).provider(:lnx) do end it "Just create bond, which unify two NICs" do + provider.class.stubs(:set_sys_class).with('/sys/class/net/bonding_masters', '+bond1').returns(true) provider.create #provider.flush end @@ -38,11 +39,11 @@ describe Puppet::Type.type(:l2_bond).provider(:lnx) do provider.class.stubs(:get_sys_class).with("/sys/class/net/bond1/bonding/slaves", true).returns([]) provider.class.stubs(:set_sys_class).with('/sys/class/net/bond1/bonding/slaves', '+eth1').returns(true) provider.class.stubs(:set_sys_class).with('/sys/class/net/bond1/bonding/slaves', '+eth2').returns(true) - provider.class.stubs(:set_interface_down).with('bond1').returns(true) - provider.class.stubs(:set_interface_down).with('bond1', true).returns(true) - provider.class.stubs(:set_interface_down).with('eth1').returns(true) - provider.class.stubs(:set_interface_down).with('eth2').returns(true) - provider.class.stubs(:get_sys_class).with('/sys/class/net/bond1/bonding/mode').returns('802.3ad') + provider.class.stubs(:interface_down).with('bond1').returns(true) + provider.class.stubs(:interface_down).with('bond1', true).returns(true) + provider.class.stubs(:interface_down).with('eth1').returns(true) + provider.class.stubs(:interface_down).with('eth2').returns(true) + provider.class.stubs(:get_sys_class).with('/sys/class/net/bond1/bonding/mode').returns('balance-rr') provider.class.stubs(:set_sys_class).with('/sys/class/net/bond1/bonding/mode', '802.3ad').returns(true) provider.class.stubs(:get_sys_class).with('/sys/class/net/bond1/bonding/xmit_hash_policy').returns('layer2') provider.class.stubs(:set_sys_class).with('/sys/class/net/bond1/bonding/xmit_hash_policy', 'layer2+3').returns(true) @@ -54,9 +55,9 @@ 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(:set_interface_up).with('bond1').returns(true) - provider.class.stubs(:set_interface_up).with('eth1').returns(true) - provider.class.stubs(:set_interface_up).with('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) provider.create #leave here as template for future #provider.expects(:warn).with { |arg| arg =~ /lnx\s+don't\s+allow\s+change\s+bond\s+slaves/ } @@ -70,4 +71,117 @@ describe Puppet::Type.type(:l2_bond).provider(:lnx) do end -end \ No newline at end of file +end + +require 'spec_helper' + +describe Puppet::Type.type(:l2_bond).provider(:lnx) do + + let(:resource) { + Puppet::Type.type(:l2_bond).new( + :provider => :lnx, + :name => 'bond2', + :slaves => ['eth12', 'eth22'], + :bond_properties => { + 'mode' => '802.3ad', + 'lacp_rate' => 'fast', + 'xmit_hash_policy' => 'layer2+3', + 'updelay' => '111', + 'downdelay' => '222', + 'ad_select' => '2', + }, + ) + } + + let(:provider) { resource.provider } + let(:instance) { provider.class.instances } + + describe "lnx bond" do + before(:each) do + puppet_debug_override() + end + + it "Do not re-assemble bond if mode is not changed" do + provider.class.stubs(:set_sys_class).with('/sys/class/net/bonding_masters', '+bond2').returns(true) + provider.create + provider.class.stubs(:get_sys_class).with("/sys/class/net/bond2/bonding/slaves", true).returns(['eth12', 'eth22']) + provider.class.expects(:set_sys_class).with('/sys/class/net/bond2/bonding/slaves', '-eth12').never + provider.class.expects(:set_sys_class).with('/sys/class/net/bond2/bonding/slaves', '-eth22').never + provider.class.stubs(:interface_down).with('bond2', true).returns(true) + provider.class.stubs(:interface_down).with('bond2').returns(true) + provider.class.stubs(:get_sys_class).with('/sys/class/net/bond2/bonding/mode').returns('802.3ad') + provider.class.expects(:set_sys_class).with('/sys/class/net/bond2/bonding/mode', '802.3ad').never + provider.class.stubs(:get_sys_class).with('/sys/class/net/bond2/bonding/xmit_hash_policy').returns('layer2') + provider.class.stubs(:set_sys_class).with('/sys/class/net/bond2/bonding/xmit_hash_policy', 'layer2+3').returns(true) + provider.class.stubs(:get_sys_class).with('/sys/class/net/bond2/bonding/lacp_rate').returns('slow') + provider.class.stubs(:set_sys_class).with('/sys/class/net/bond2/bonding/lacp_rate', 'fast').returns(true) + provider.class.stubs(:get_sys_class).with('/sys/class/net/bond2/bonding/ad_select').returns('stable') + provider.class.stubs(:set_sys_class).with('/sys/class/net/bond2/bonding/ad_select', '2').returns(true) + provider.class.stubs(:get_sys_class).with('/sys/class/net/bond2/bonding/updelay').returns('0') + provider.class.stubs(:set_sys_class).with('/sys/class/net/bond2/bonding/updelay', '111').returns(true) + provider.class.stubs(:get_sys_class).with('/sys/class/net/bond2/bonding/downdelay').returns('0') + provider.class.stubs(:set_sys_class).with('/sys/class/net/bond2/bonding/downdelay', '222').returns(true) + provider.class.expects(:set_sys_class).with('/sys/class/net/bond2/bonding/slaves', '+eth12').never + provider.class.expects(:set_sys_class).with('/sys/class/net/bond2/bonding/slaves', '+eth22').never + provider.class.stubs(:interface_up).with('bond2').returns(true) + provider.class.stubs(:interface_up).with('bond2', true).returns(true) + provider.flush + end + end +end + +describe Puppet::Type.type(:l2_bond).provider(:lnx) do + + let(:resource) { + Puppet::Type.type(:l2_bond).new( + :provider => :lnx, + :name => 'bond3', + :slaves => ['eth31', 'eth32'], + :bond_properties => { + 'mode' => '802.3ad', + 'lacp_rate' => 'fast', + 'xmit_hash_policy' => 'layer2+3', + 'updelay' => '111', + 'downdelay' => '222', + 'ad_select' => '2', + }, + ) + } + + let(:provider) { resource.provider } + let(:instance) { provider.class.instances } + + describe "lnx bond" do + before(:each) do + puppet_debug_override() + end + + it "Do not down/up bond if nothing changed" do + provider.class.stubs(:set_sys_class).with('/sys/class/net/bonding_masters', '+bond3').returns(true) + provider.class.stubs(:get_iface_state).with('bond3').returns(true) + provider.create + provider.class.stubs(:get_sys_class).with("/sys/class/net/bond3/bonding/slaves", true).returns(['eth31', 'eth32']) + provider.class.expects(:set_sys_class).with('/sys/class/net/bond3/bonding/slaves', '-eth31').never + provider.class.expects(:set_sys_class).with('/sys/class/net/bond3/bonding/slaves', '-eth32').never + provider.class.stubs(:interface_down).with('bond3', true).never + provider.class.stubs(:interface_down).with('bond3').never + provider.class.stubs(:get_sys_class).with('/sys/class/net/bond3/bonding/mode').returns('802.3ad') + provider.class.expects(:set_sys_class).with('/sys/class/net/bond3/bonding/mode', '802.3ad').never + provider.class.stubs(:get_sys_class).with('/sys/class/net/bond3/bonding/xmit_hash_policy').returns('layer2+3') + provider.class.stubs(:set_sys_class).with('/sys/class/net/bond3/bonding/xmit_hash_policy', 'layer2+3').never + provider.class.stubs(:get_sys_class).with('/sys/class/net/bond3/bonding/lacp_rate').returns('fast') + provider.class.stubs(:set_sys_class).with('/sys/class/net/bond3/bonding/lacp_rate', 'fast').never + provider.class.stubs(:get_sys_class).with('/sys/class/net/bond3/bonding/ad_select').returns('2') + provider.class.stubs(:set_sys_class).with('/sys/class/net/bond3/bonding/ad_select', '2').never + provider.class.stubs(:get_sys_class).with('/sys/class/net/bond3/bonding/updelay').returns('111') + provider.class.stubs(:set_sys_class).with('/sys/class/net/bond3/bonding/updelay', '111').never + provider.class.stubs(:get_sys_class).with('/sys/class/net/bond3/bonding/downdelay').returns('222') + provider.class.stubs(:set_sys_class).with('/sys/class/net/bond3/bonding/downdelay', '222').never + provider.class.expects(:set_sys_class).with('/sys/class/net/bond3/bonding/slaves', '+eth31').never + provider.class.expects(:set_sys_class).with('/sys/class/net/bond3/bonding/slaves', '+eth32').never + provider.class.stubs(:interface_up).with('bond3').never + provider.class.stubs(:interface_up).with('bond3', true).never + provider.flush + end + end +end