Add new bond propertiew configuration:

New properties are:
* downdelay
* updelay
* ad_select

Also implemented:
* improved tests
* replace some iproute() to corresponded class methods
* modifyed arping arguments
* move some interface-related methods to InterfaceToolset base class

implementation progress:
+ l23_stored_config_for LNX-ubuntu
+ l23_stored_config_for OVS-ubuntu
- l23_stored_config_for LNX-centos
- l23_stored_config_for OVS-centos
+ runtime configuration for LNX
+ runtime configuration for OVS

Change-Id: I3c144f410c29c114c7976a43f5fd00967ae601a4
This commit is contained in:
Sergey Vasilenko
2015-09-08 14:25:11 -05:00
parent 1811b2f47b
commit cb5c8ad096
25 changed files with 546 additions and 298 deletions

View File

@@ -0,0 +1,229 @@
require 'puppetx/l23_utils'
require 'yaml'
class Puppet::Provider::InterfaceToolset < Puppet::Provider
def self.iproute(*cmd)
actual_cmd = ['ip'] + Array(*cmd)
rv = []
IO.popen(actual_cmd.join(' ') + ' 2>&1') do |ff|
rv = ff.readlines().map{|l| l.chomp()}
ff.close
if 0 != $?.exitstatus
raise Puppet::ExecutionFailure, "Command '#{actual_cmd.join(' ')}' has been failed with exit_code=#{$?.exitstatus}:\n#{rv.join("\n")}"
end
end
return rv
end
def self.ovs_vsctl(*cmd)
actual_cmd = ['ovs-vsctl'] + Array(*cmd)
rv = []
IO.popen(actual_cmd.join(' ') + ' 2>&1') do |ff|
rv = ff.readlines().map{|l| l.chomp()}
ff.close
if 0 != $?.exitstatus
rv = nil
end
end
return rv
end
# ---------------------------------------------------------------------------
def self.iface_exist?(iface)
File.exist? "/sys/class/net/#{iface}"
end
def self.set_mtu(iface, mtu=1500)
if File.symlink?("/sys/class/net/#{iface}")
debug("Set MTU to '#{mtu}' for interface '#{iface}'")
set_sys_class("/sys/class/net/#{iface}/mtu", mtu)
end
end
# ---------------------------------------------------------------------------
def self.set_sys_class(property, value)
debug("SET sys.property: #{property} << #{value}")
begin
property_file = File.open(property, 'a')
property_file.write("#{value.to_s}")
property_file.close
rv = true
rescue Exception => e
debug("Non-fatal-Error: Can't set property '#{property}' to '#{value}': #{e.message}")
rv = false
end
return rv
end
def self.get_sys_class(property, array=false)
as_array = (array ? ' as array' : '')
debug("GET sys.property: #{property}#{as_array}.")
begin
rv = File.open(property).read.split(/\s+/)
rescue Exception => e
debug("Non-fatal-Error: Can't get property '#{property}': #{e.message}")
rv = ['']
end
(array ? rv : rv[0])
end
# ---------------------------------------------------------------------------
def self.get_iface_state(iface)
# returns:
# true -- interface in UP state
# false -- interface in UP state, but no-carrier
# nil -- interface in DOWN state
begin
1 == File.open("/sys/class/net/#{iface}/carrier").read.chomp.to_i
rescue
# if interface is down, this file can't be read
nil
end
end
def self.interface_up(iface, force=false)
cmd = ['link', 'set', 'up', 'dev', iface]
cmd.insert(0, '--force') if force
begin
iproute(cmd)
rv = true
rescue Exception => e
debug("Non-fatal-Error: Can't put interface '#{iface}' to UP state: #{e.message}")
rv = false
end
return rv
end
def self.interface_down(iface, force=false)
cmd = ['link', 'set', 'down', 'dev', iface]
cmd.insert(0, '--force') if force
begin
iproute(cmd)
rv = true
rescue Exception => e
debug("Non-fatal-Error: Can't put interface '#{iface}' to DOWN state: #{e.message}")
rv = false
end
return rv
end
# ---------------------------------------------------------------------------
def self.ipaddr_exist?(if_name)
rv = false
iproute(['-o', 'addr', 'show', 'dev', if_name]).map{|l| l.split(/\s+/)}.each do |line|
if line[2].match(/^inet\d?$/)
rv=true
break
end
end
return rv
end
def self.addr_flush(iface, force=false)
cmd = ['addr', 'flush', 'dev', iface]
cmd.insert(0, '--force') if force
begin
iproute(cmd)
rv = true
rescue Exception => e
debug("Non-fatal-Error: Can't flush addr for interface '#{iface}': #{e.message}")
rv = false
end
return rv
end
def self.route_flush(iface, force=false)
cmd = ['route', 'flush', 'dev', iface]
cmd.insert(0, '--force') if force
begin
iproute(cmd)
rv = true
rescue Exception => e
debug("Non-fatal-Error: Can't flush routes for interface '#{iface}': #{e.message}")
rv = false
end
return rv
end
# ---------------------------------------------------------------------------
def self.get_if_addr_mappings
if_list = {}
ip_a = iproute(['-f', 'inet', 'addr', 'show'])
if_name = nil
ip_a.each do |line|
line.rstrip!
case line
when /^\s*\d+\:\s+([\w\-\.]+)[\:\@]/i
if_name = $1
if_list[if_name] = { :ipaddr => [] }
when /^\s+inet\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/\d{1,2})/
next if if_name.nil?
if_list[if_name][:ipaddr] << $1
else
next
end
end
return if_list
end
def self.get_if_defroutes_mappings
rou_list = {}
ip_a = iproute(['-f', 'inet', 'route', 'show'])
ip_a.each do |line|
line.rstrip!
next if !line.match(/^\s*default\s+via\s+([\d\.]+)\s+dev\s+([\w\-\.]+)(\s+metric\s+(\d+))?/)
metric = $4.nil? ? :absent : $4.to_i
rou_list[$2] = { :gateway => $1, :gateway_metric => metric } if rou_list[$2].nil? # do not replace to gateway with highest metric
end
return rou_list
end
def self.get_routes
# return array of hashes -- all defined routes.
rv = []
# cat /proc/net/route returns information about routing table in format:
# Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
# eth0 00000000 0101010A 0003 0 0 0 00000000 0 0 0
# eth0 0001010A 00000000 0001 0 0 0 00FFFFFF 0 0 0
File.open('/proc/net/route').readlines.reject{|l| l.match(/^[Ii]face.+/) or l.match(/^(\r\n|\n|\s*)$|^$/)}.map{|l| l.split(/\s+/)}.each do |line|
#https://github.com/kwilczynski/facter-facts/blob/master/default_gateway.rb
iface = line[0]
metric = line[6]
# whether gateway is default
if line[1] == '00000000'
dest = 'default'
dest_addr = nil
mask = nil
route_type = 'default'
else
dest_addr = [line[1]].pack('H*').unpack('C4').reverse.join('.')
mask = [line[7]].pack('H*').unpack('B*')[0].count('1')
dest = "#{dest_addr}/#{mask}"
end
# whether route is local
if line[2] == '00000000'
gateway = nil
route_type = 'local'
else
gateway = [line[2]].pack('H*').unpack('C4').reverse.join('.')
route_type = nil
end
rv << {
:destination => dest,
:gateway => gateway,
:metric => metric.to_i,
:type => route_type,
:interface => iface,
}
end
# this sort need for prioritize routes by metrics
return rv.sort_by{|r| r[:metric]||0}
end
end
# vim: set ts=2 sw=2 et :

View File

@@ -1,5 +1,3 @@
require File.join(File.dirname(__FILE__), '..','..','..','puppet/provider/lnx_base')
Puppet::Type.type(:k_mod).provide(:lnx) do
defaultfor :osfamily => :linux
commands :mod_load => 'modprobe',

View File

@@ -22,6 +22,9 @@ Puppet::Type.type(:l23_stored_config).provide(:ovs_ubuntu, :parent => Puppet::Pr
:bond_lacp_rate => 'ovs_options',
:bond_lacp => 'ovs_options',
:bond_xmit_hash_policy => '', # unused
:bond_ad_select => '',
:bond_updelay => 'ovs_options',
:bond_downdelay => 'ovs_options',
})
return rv
end
@@ -34,6 +37,14 @@ Puppet::Type.type(:l23_stored_config).provide(:ovs_ubuntu, :parent => Puppet::Pr
:field => 'bond_mode',
:store_to => 'ovs_options'
},
:bond_updelay => {
:field => 'bond_updelay',
:store_to => 'ovs_options'
},
:bond_downdelay => {
:field => 'bond_downdelay',
:store_to => 'ovs_options'
},
:bond_lacp => {
:field => 'lacp',
:store_to => 'ovs_options'
@@ -46,7 +57,6 @@ Puppet::Type.type(:l23_stored_config).provide(:ovs_ubuntu, :parent => Puppet::Pr
:field => 'other_config:bond-miimon-interval',
:store_to => 'ovs_options'
},
}
end
def oneline_properties

View File

@@ -31,6 +31,9 @@ class Puppet::Provider::L23_stored_config_ubuntu < Puppet::Provider::L23_stored_
:bond_miimon => 'bond-miimon',
:bond_lacp => '', # unused for lnx
:bond_lacp_rate => 'bond-lacp-rate',
:bond_updelay => 'bond-updelay',
:bond_downdelay => 'bond-downdelay',
:bond_ad_select => 'bond-ad-select',
:bond_xmit_hash_policy => 'bond-xmit-hash-policy'
}
end

View File

@@ -1,19 +1,7 @@
require 'puppetx/l23_utils'
require 'puppetx/l23_ethtool_name_commands_mapping'
require 'yaml'
require File.join(File.dirname(__FILE__), 'interface_toolset')
class Puppet::Provider::L2_base < Puppet::Provider
def self.ovs_vsctl(*cmd)
actual_cmd = ['ovs-vsctl'] + Array(*cmd)
begin
ff = IO.popen(actual_cmd.join(' '))
rv = ff.readlines().map{|l| l.chomp()}
rescue
rv = nil
end
return rv
end
class Puppet::Provider::L2_base < Puppet::Provider::InterfaceToolset
def self.prefetch(resources)
interfaces = instances
@@ -26,10 +14,6 @@ class Puppet::Provider::L2_base < Puppet::Provider
# ---------------------------------------------------------------------------
def self.iface_exist?(iface)
File.exist? "/sys/class/net/#{iface}"
end
def self.get_lnx_vlan_interfaces
# returns hash, that contains ports (interfaces) configuration.
# i.e {
@@ -583,31 +567,6 @@ class Puppet::Provider::L2_base < Puppet::Provider
self.ovs_bond_allowed_properties.keys.sort
end
def self.get_iface_state(iface)
# returns:
# true -- interface in UP state
# false -- interface in UP state, but no-carrier
# nil -- interface in DOWN state
begin
1 == File.open("/sys/class/net/#{iface}/carrier").read.chomp.to_i
rescue
# if interface is down, this file can't be read
nil
end
end
def self.ipaddr_exist?(if_name)
rv = false
iproute('-o', 'addr', 'show', 'dev', if_name).split(/\n+/).map{|l| l.split(/\s+/)}.each do |line|
if line[2].match(/^inet\d?$/)
rv=true
break
end
end
return rv
end
# ---------------------------------------------------------------------------
def self.get_ethtool_name_commands_mapping
@@ -628,35 +587,6 @@ class Puppet::Provider::L2_base < Puppet::Provider
# ---------------------------------------------------------------------------
def self.set_sys_class(property, value)
begin
property_file = File.open(property, 'a')
property_file.write("#{value.to_s}")
property_file.close
rescue Exception => e
debug("Non-fatal-Error: Can't set property '#{property}' to '#{value}': #{e.message}")
end
end
def self.get_sys_class(property, array=false)
begin
rv = File.open(property).read.split(/\s+/)
rescue Exception => e
debug("Non-fatal-Error: Can't get property '#{property}': #{e.message}")
rv = ['']
end
(array ? rv : rv[0])
end
# ---------------------------------------------------------------------------
def self.set_mtu(iface, mtu=1500)
if File.symlink?("/sys/class/net/#{iface}")
debug("Set MTU to '#{mtu}' for interface '#{iface}'")
File.open("/sys/class/net/#{iface}/mtu", "a") { |f| f.write(mtu) }
end
end
end
# vim: set ts=2 sw=2 et :

View File

@@ -6,8 +6,7 @@ require File.join(File.dirname(__FILE__), '..','..','..','puppet/provider/lnx_ba
Puppet::Type.type(:l2_bond).provide(:lnx, :parent => Puppet::Provider::Lnx_base) do
defaultfor :osfamily => :linux
commands :iproute => 'ip',
:ethtool_cmd => 'ethtool',
commands :ethtool_cmd => 'ethtool',
:brctl => 'brctl'
@@ -56,16 +55,12 @@ Puppet::Type.type(:l2_bond).provide(:lnx, :parent => Puppet::Provider::Lnx_base)
debug("CREATE resource: #{@resource}")
@old_property_hash = {}
@property_flush = {}.merge! @resource
open('/sys/class/net/bonding_masters', 'a') do |f|
f << "+#{@resource[:name]}"
end
self.class.set_sys_class('/sys/class/net/bonding_masters', "+#{@resource[:name]}")
end
def destroy
debug("DESTROY resource: #{@resource}")
open('/sys/class/net/bonding_masters', 'a') do |f|
f << "-#{@resource[:name]}"
end
self.class.set_sys_class('/sys/class/net/bonding_masters', "-#{@resource[:name]}")
end
def flush
@@ -75,7 +70,7 @@ Puppet::Type.type(:l2_bond).provide(:lnx, :parent => Puppet::Provider::Lnx_base)
#
# FLUSH changed properties
if @property_flush.has_key? :slaves
runtime_slave_ports = File.open("/sys/class/net/#{@resource[:bond]}/bonding/slaves", "r").read.split(/\s+/)
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
@@ -84,7 +79,7 @@ Puppet::Type.type(:l2_bond).provide(:lnx, :parent => Puppet::Provider::Lnx_base)
if !rm_slave_list.empty?
debug("Remove '#{rm_slave_list.join(',')}' ports from bond '#{@resource[:bond]}'")
rm_slave_list.each do |slave|
iproute('link', 'set', 'down', 'dev', slave) # need by kernel requirements by design. undocumented :(
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
@@ -94,9 +89,9 @@ Puppet::Type.type(:l2_bond).provide(:lnx, :parent => Puppet::Provider::Lnx_base)
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]}'")
iproute('link', 'set', 'down', 'dev', slave) # need by kernel requirements by design. undocumented :(
self.class.interface_down(slave) # need by kernel requirements by design. undocumented :(
self.class.set_sys_class("#{bond_prop_dir}/bonding/slaves", "+#{slave}")
iproute('link', 'set', 'up', 'dev', slave)
self.class.interface_up(slave)
end
end
end
@@ -115,7 +110,7 @@ Puppet::Type.type(:l2_bond).provide(:lnx, :parent => Puppet::Provider::Lnx_base)
# says, that bond interface should be downed, but it's not enouth.
self.class.set_sys_class("#{bond_prop_dir}/bonding/slaves", "-#{eth}")
end
iproute('link', 'set', 'down', 'dev', @resource[:bond])
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]}'")
@@ -155,7 +150,7 @@ Puppet::Type.type(:l2_bond).provide(:lnx, :parent => Puppet::Provider::Lnx_base)
end
end
# re-assemble bond after configuration
iproute('link', 'set', 'up', 'dev', @resource[:bond]) if runtime_bond_state
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]}'")
@@ -172,7 +167,7 @@ Puppet::Type.type(:l2_bond).provide(:lnx, :parent => Puppet::Provider::Lnx_base)
#
# remove interface from old bridge
runtime_bond_state = !self.class.get_iface_state(@resource[:bond]).nil?
iproute('--force', 'link', 'set', 'down', 'dev', @resource[:bond])
self.class.interface_down(@resource[:bond], true)
if ! port_bridges_hash[@resource[:bond]].nil?
br_name = port_bridges_hash[@resource[:bond]][:bridge]
if br_name != @resource[:bond]
@@ -200,11 +195,11 @@ Puppet::Type.type(:l2_bond).provide(:lnx, :parent => Puppet::Provider::Lnx_base)
#pass
end
end
iproute('link', 'set', 'up', 'dev', @resource[:bond]) if runtime_bond_state
self.class.interface_up(@resource[:bond]) if runtime_bond_state
debug("Change bridge")
end
if @property_flush[:onboot]
iproute('link', 'set', 'up', 'dev', @resource[:bond])
self.class.interface_up(@resource[:bond])
end
if !['', 'absent'].include? @property_flush[:mtu].to_s
self.class.set_mtu(@resource[:bond], @property_flush[:mtu])

View File

@@ -2,8 +2,7 @@ require File.join(File.dirname(__FILE__), '..','..','..','puppet/provider/ovs_ba
Puppet::Type.type(:l2_bond).provide(:ovs, :parent => Puppet::Provider::Ovs_base) do
commands :vsctl => 'ovs-vsctl',
:ethtool_cmd => 'ethtool',
:iproute => 'ip'
:ethtool_cmd => 'ethtool'
# def self.add_unremovable_flag(port_props)
@@ -26,7 +25,7 @@ Puppet::Type.type(:l2_bond).provide(:ovs, :parent => Puppet::Provider::Ovs_base)
@property_flush = {}.merge! @resource
@resource[:slaves].each do |slave|
iproute('addr', 'flush', 'dev', slave)
self.class.addr_flush(slave)
end
begin

View File

@@ -9,8 +9,7 @@ require File.join(File.dirname(__FILE__), '..','..','..','puppet/provider/lnx_ba
Puppet::Type.type(:l2_bridge).provide(:lnx, :parent => Puppet::Provider::Lnx_base) do
defaultfor :osfamily => :linux
commands :brctl => 'brctl',
:ethtool_cmd => 'ethtool',
:iproute => 'ip'
:ethtool_cmd => 'ethtool'
def self.instances
rv = []
@@ -44,11 +43,11 @@ Puppet::Type.type(:l2_bridge).provide(:lnx, :parent => Puppet::Provider::Lnx_bas
raise if ! self.class.iface_exist? @resource[:bridge]
notice("'#{@resource[:bridge]}' already created by ghost event.")
end
iproute('link', 'set', 'up', 'dev', @resource[:bridge])
self.class.interface_up(@resource[:bridge])
end
def destroy
iproute('link', 'set', 'down', 'dev', @resource[:bridge])
self.class.interface_down(@resource[:bridge])
brctl('delbr', @resource[:bridge])
end

View File

@@ -3,8 +3,7 @@ require File.join(File.dirname(__FILE__), '..','..','..','puppet/provider/ovs_ba
Puppet::Type.type(:l2_bridge).provide(:ovs, :parent => Puppet::Provider::Ovs_base) do
commands :vsctl => 'ovs-vsctl',
:ethtool_cmd => 'ethtool',
:brctl => 'brctl',
:iproute => 'ip'
:brctl => 'brctl'
def self.skip_port_for?(port_props)
port_props[:br_type] != 'ovs'
@@ -27,12 +26,12 @@ Puppet::Type.type(:l2_bridge).provide(:ovs, :parent => Puppet::Provider::Ovs_bas
@property_flush = {}.merge! @resource
#
vsctl('add-br', @resource[:bridge])
iproute('link', 'set', 'up', 'dev', @resource[:bridge])
self.class.interface_up(@resource[:bridge])
notice("bridge '#{@resource[:bridge]}' created.")
end
def destroy
iproute('link', 'set', 'down', 'dev', @resource[:bridge])
self.class.interface_down(@resource[:bridge])
vsctl("del-br", @resource[:bridge])
end

View File

@@ -4,8 +4,7 @@ require File.join(File.dirname(__FILE__), '..','..','..','puppet/provider/ovs_ba
Puppet::Type.type(:l2_patch).provide(:ovs, :parent => Puppet::Provider::Ovs_base) do
commands :vsctl => 'ovs-vsctl',
:ethtool_cmd => 'ethtool',
:brctl => 'brctl',
:iproute => 'ip'
:brctl => 'brctl'
def self.instances
@@ -107,7 +106,7 @@ Puppet::Type.type(:l2_patch).provide(:ovs, :parent => Puppet::Provider::Ovs_base
end
end
end
iproute('link', 'set', 'up', 'dev', jack)
self.class.interface_up(jack)
else
# creating OVS-to-OVS patchcord
jacks = []

View File

@@ -2,8 +2,7 @@ require File.join(File.dirname(__FILE__), '..','..','..','puppet/provider/lnx_ba
Puppet::Type.type(:l2_port).provide(:lnx, :parent => Puppet::Provider::Lnx_base) do
defaultfor :osfamily => :linux
commands :iproute => 'ip',
:ethtool_cmd => 'ethtool',
commands :ethtool_cmd => 'ethtool',
:brctl => 'brctl',
:pkill => 'pkill'
@@ -47,7 +46,7 @@ Puppet::Type.type(:l2_port).provide(:lnx, :parent => Puppet::Provider::Lnx_base)
@property_flush = {}.merge! @resource
# todo: divide simple creating interface and vlan
begin
iproute('link', 'add', 'link', @resource[:vlan_dev], 'name', @resource[:interface], 'type', 'vlan', 'id', @resource[:vlan_id])
self.class.iproute(['link', 'add', 'link', @resource[:vlan_dev], 'name', @resource[:interface], 'type', 'vlan', 'id', @resource[:vlan_id]])
rescue
# Some time interface may be created by OS init scripts. It's a normal for Ubuntu.
raise if ! self.class.iface_exist? @resource[:interface]
@@ -59,7 +58,7 @@ Puppet::Type.type(:l2_port).provide(:lnx, :parent => Puppet::Provider::Lnx_base)
debug("DESTROY resource: #{@resource}")
# todo: Destroing of L2 resource -- is a putting interface to the DOWN state.
# Or remove, if ove a vlan interface
#iproute('--force', 'addr', 'flush', 'dev', @resource[:interface])
#iproute(['--force', 'addr', 'flush', 'dev', @resource[:interface]])
end
def flush
@@ -77,10 +76,10 @@ Puppet::Type.type(:l2_port).provide(:lnx, :parent => Puppet::Provider::Lnx_base)
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
iproute('addr', 'flush', 'dev', @resource[:interface])
self.class.addr_flush(@resource[:interface])
end
# putting interface to the down-state, because add/remove upped interface impossible. undocumented kern.behavior.
iproute('--force', 'link', 'set', 'down', 'dev', @resource[:interface])
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}'.")
@@ -99,9 +98,9 @@ Puppet::Type.type(:l2_port).provide(:lnx, :parent => Puppet::Provider::Lnx_base)
@property_flush[:port_type] = nil
end
# Up parent interface if this is vlan port
iproute('link', 'set', 'up', 'dev', @resource[:vlan_dev]) if @resource[:vlan_dev]
self.class.interface_up(@resource[:vlan_dev]) if @resource[:vlan_dev]
# Up port
iproute('link', 'set', 'up', 'dev', @resource[:interface])
self.class.interface_up(@resource[:interface])
end
if @property_flush.has_key? :bridge
# get actual bridge-list. We should do it here,
@@ -112,9 +111,9 @@ Puppet::Type.type(:l2_port).provide(:lnx, :parent => Puppet::Provider::Lnx_base)
debug("Actual-port-bridge-mapping: '#{port_bridges_hash}'") # it should removed from LNX
#
#Flush ipaddr and routes for interface, thah adding to the bridge
iproute('route', 'flush', 'dev', @resource[:interface])
iproute('addr', 'flush', 'dev', @resource[:interface])
iproute('--force', 'link', 'set', 'down', 'dev', @resource[:interface])
self.class.route_flush(@resource[:interface])
self.class.addr_flush(@resource[:interface])
self.class.interface_down(@resource[:interface], true)
# remove interface from old bridge
if ! port_bridges_hash[@resource[:interface]].nil?
br_name = port_bridges_hash[@resource[:interface]][:bridge]
@@ -149,7 +148,7 @@ Puppet::Type.type(:l2_port).provide(:lnx, :parent => Puppet::Provider::Lnx_base)
#pass
end
end
iproute('link', 'set', 'up', 'dev', @resource[:interface])
self.class.interface_up(@resource[:interface])
debug("Change bridge")
end
if @property_flush.has_key? :ethtool and @property_flush[:ethtool].is_a? Hash
@@ -176,9 +175,9 @@ Puppet::Type.type(:l2_port).provide(:lnx, :parent => Puppet::Provider::Lnx_base)
# Should be after bond, because interface may auto-upped while added to the bond
debug("Setup UP state for interface '#{@resource[:interface]}'.")
# Up parent interface if this is vlan port
iproute('link', 'set', 'up', 'dev', @resource[:vlan_dev]) if @resource[:vlan_dev]
self.class.interface_up(@resource[:vlan_dev]) if @resource[:vlan_dev]
# Up port
iproute('link', 'set', 'up', 'dev', @resource[:interface])
self.class.interface_up(@resource[:interface])
end
if !['', 'absent'].include? @property_flush[:mtu].to_s
self.class.set_mtu(@resource[:interface], @property_flush[:mtu])

View File

@@ -2,9 +2,7 @@ require File.join(File.dirname(__FILE__), '..','..','..','puppet/provider/ovs_ba
Puppet::Type.type(:l2_port).provide(:ovs, :parent => Puppet::Provider::Ovs_base) do
commands :vsctl => 'ovs-vsctl',
:ethtool_cmd => 'ethtool',
:iproute => 'ip'
:ethtool_cmd => 'ethtool'
def self.add_unremovable_flag(port_props)
# calculate 'unremovable' flag. Should be re-defined in chield providers

View File

@@ -0,0 +1,16 @@
require File.join(File.dirname(__FILE__), 'interface_toolset')
class Puppet::Provider::L3_base < Puppet::Provider::InterfaceToolset
def self.prefetch(resources)
interfaces = instances
resources.keys.each do |name|
if provider = interfaces.find{ |ii| ii.name == name }
resources[name].provider = provider
end
end
end
end
# vim: set ts=2 sw=2 et :

View File

@@ -1,20 +1,11 @@
Puppet::Type.type(:l3_ifconfig).provide(:lnx) do
require File.join(File.dirname(__FILE__), '..','..','..','puppet/provider/l3_base')
Puppet::Type.type(:l3_ifconfig).provide(:lnx, :parent => Puppet::Provider::L3_base) do
defaultfor :osfamily => :linux
commands :iproute => 'ip',
:ifup => 'ifup',
commands :ifup => 'ifup',
:ifdown => 'ifdown',
:arping => 'arping'
def self.prefetch(resources)
interfaces = instances
resources.keys.each do |name|
if provider = interfaces.find{ |ii| ii.name == name }
resources[name].provider = provider
end
end
end
def self.instances
insts = []
rou_list = self.get_if_defroutes_mappings()
@@ -56,7 +47,7 @@ Puppet::Type.type(:l3_ifconfig).provide(:lnx) do
debug("DESTROY resource: #{@resource}")
# todo: Destroing of L3 resource -- is a removing any IP addresses.
# DO NOT!!! put intedafce to Down state.
iproute('--force', 'addr', 'flush', 'dev', @resource[:interface])
self.class.addr_flush(@resource[:interface], true)
@property_hash.clear
end
@@ -75,7 +66,7 @@ Puppet::Type.type(:l3_ifconfig).provide(:lnx) do
if ! @property_flush[:ipaddr].nil?
if @property_flush[:ipaddr].include?(:absent)
# flush all ip addresses from interface
iproute('--force', 'addr', 'flush', 'dev', @resource[:interface])
self.class.addr_flush(@resource[:interface], true)
#todo(sv): check for existing dhclient for this interface and kill it
elsif (@property_flush[:ipaddr] & [:dhcp, 'dhcp', 'DHCP']).any?
# start dhclient on interface the same way as at boot time
@@ -86,14 +77,14 @@ Puppet::Type.type(:l3_ifconfig).provide(:lnx) do
# add-remove static IP addresses
if !@old_property_hash.nil? and !@old_property_hash[:ipaddr].nil?
(@old_property_hash[:ipaddr] - @property_flush[:ipaddr]).each do |ipaddr|
iproute('--force', 'addr', 'del', ipaddr, 'dev', @resource[:interface])
self.class.iproute(['--force', 'addr', 'del', ipaddr, 'dev', @resource[:interface]])
end
adding_addresses = @property_flush[:ipaddr] - @old_property_hash[:ipaddr]
else
adding_addresses = @property_flush[:ipaddr]
end
if adding_addresses.include? :none
iproute('--force', 'link', 'set', 'dev', @resource[:interface], 'up')
self.class.interface_up(@resource[:interface], true)
elsif adding_addresses.include? :dhcp
debug("!!! DHCP runtime configuration not implemented now !!!")
else
@@ -101,7 +92,7 @@ Puppet::Type.type(:l3_ifconfig).provide(:lnx) do
adding_addresses.each do |ipaddr|
# Check whether IP address is already used
begin
arping('-D', '-c 32', '-w 5', '-I', @resource[:interface], ipaddr.split('/')[0])
arping(['-D', '-f', '-c 32', '-w 2', '-I', @resource[:interface], ipaddr.split('/')[0]])
rescue Exception => e
_errmsg = nil
e.message.split(/\n/).each do |line|
@@ -116,13 +107,13 @@ Puppet::Type.type(:l3_ifconfig).provide(:lnx) do
end
# Set IP address
begin
iproute('addr', 'add', ipaddr, 'dev', @resource[:interface])
self.class.iproute(['addr', 'add', ipaddr, 'dev', @resource[:interface]])
rescue
rv = iproute('-o', 'addr', 'show', 'dev', @resource[:interface], 'to', "#{ipaddr.split('/')[0]}/32")
raise if ! rv.include? "inet #{ipaddr}"
rv = self.class.iproute(['-o', 'addr', 'show', 'dev', @resource[:interface], 'to', "#{ipaddr.split('/')[0]}/32"])
raise if ! rv.join("\n").include? "inet #{ipaddr}"
end
# Send Gratuitous ARP to update all neighbours
arping('-U', '-c 32', '-w 5', '-I', @resource[:interface], ipaddr.split('/')[0])
arping(['-A', '-c 32', '-w 2', '-I', @resource[:interface], ipaddr.split('/')[0]])
end
end
end
@@ -137,7 +128,7 @@ Puppet::Type.type(:l3_ifconfig).provide(:lnx) do
# when has multiple default routes through the same router,
# but with different metrics
begin
iproute(cmdline)
self.class.iproute(cmdline)
rescue
break
end
@@ -155,11 +146,11 @@ Puppet::Type.type(:l3_ifconfig).provide(:lnx) do
cmdline << ['metric', @property_flush[:gateway_metric]]
end
begin
rv = iproute(cmdline)
self.class.iproute(cmdline)
rescue
warn("!!! Iproute can not setup new gateway.\n!!! May be default gateway with same metric already exists:")
rv = iproute('-f', 'inet', 'route', 'show')
warn("#{rv}\n\n")
rv = self.class.iproute(['-f', 'inet', 'route', 'show'])
warn("#{rv.join("\n")}\n\n")
end
end
end
@@ -233,37 +224,6 @@ Puppet::Type.type(:l3_ifconfig).provide(:lnx) do
#-----------------------------------------------------------------
def self.get_if_addr_mappings
if_list = {}
ip_a = iproute('-f', 'inet', 'addr', 'show').split(/\n+/)
if_name = nil
ip_a.each do |line|
line.rstrip!
case line
when /^\s*\d+\:\s+([\w\-\.]+)[\:\@]/i
if_name = $1
if_list[if_name] = { :ipaddr => [] }
when /^\s+inet\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/\d{1,2})/
next if if_name.nil?
if_list[if_name][:ipaddr] << $1
else
next
end
end
return if_list
end
def self.get_if_defroutes_mappings
rou_list = {}
ip_a = iproute('-f', 'inet', 'route', 'show').split(/\n+/)
ip_a.each do |line|
line.rstrip!
next if !line.match(/^\s*default\s+via\s+([\d\.]+)\s+dev\s+([\w\-\.]+)(\s+metric\s+(\d+))?/)
metric = $4.nil? ? :absent : $4.to_i
rou_list[$2] = { :gateway => $1, :gateway_metric => metric } if rou_list[$2].nil? # do not replace to gateway with highest metric
end
return rou_list
end
end

View File

@@ -1,62 +1,10 @@
require 'ipaddr'
require 'yaml'
require 'puppetx/l23_utils'
# require 'yaml'
# require 'puppetx/l23_utils'
require File.join(File.dirname(__FILE__), '..','..','..','puppet/provider/l3_base')
Puppet::Type.type(:l3_route).provide(:lnx) do
Puppet::Type.type(:l3_route).provide(:lnx, :parent => Puppet::Provider::L3_base) do
defaultfor :osfamily => :linux
commands :iproute => 'ip'
def self.prefetch(resources)
interfaces = instances
resources.keys.each do |name|
if provider = interfaces.find{ |ii| ii.name == name }
resources[name].provider = provider
end
end
end
def self.get_routes
# return array of hashes -- all defined routes.
rv = []
# cat /proc/net/route returns information about routing table in format:
# Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
# eth0 00000000 0101010A 0003 0 0 0 00000000 0 0 0
# eth0 0001010A 00000000 0001 0 0 0 00FFFFFF 0 0 0
File.open('/proc/net/route').readlines.reject{|l| l.match(/^[Ii]face.+/) or l.match(/^(\r\n|\n|\s*)$|^$/)}.map{|l| l.split(/\s+/)}.each do |line|
#https://github.com/kwilczynski/facter-facts/blob/master/default_gateway.rb
iface = line[0]
metric = line[6]
# whether gateway is default
if line[1] == '00000000'
dest = 'default'
dest_addr = nil
mask = nil
route_type = 'default'
else
dest_addr = [line[1]].pack('H*').unpack('C4').reverse.join('.')
mask = [line[7]].pack('H*').unpack('B*')[0].count('1')
dest = "#{dest_addr}/#{mask}"
end
# whether route is local
if line[2] == '00000000'
gateway = nil
route_type = 'local'
else
gateway = [line[2]].pack('H*').unpack('C4').reverse.join('.')
route_type = nil
end
rv << {
:destination => dest,
:gateway => gateway,
:metric => metric.to_i,
:type => route_type,
:interface => iface,
}
end
# this sort need for prioritize routes by metrics
return rv.sort_by{|r| r[:metric]||0}
end
def self.instances
rv = []
@@ -86,7 +34,7 @@ Puppet::Type.type(:l3_route).provide(:lnx) do
cmd = ['route', 'add', @resource[:destination], 'via', @resource[:gateway]]
cmd << ['metric', @resource[:metric]] if @resource[:metric] != :absent && @resource[:metric].to_i > 0
begin
iproute(cmd)
self.class.iproute(cmd)
rescue Exception => e
if e.to_s =~ /File\s+exists/
notice("Route for '#{@resource[:destination]}' via #{@resource[:gateway]} already exists. Use existing...")
@@ -104,7 +52,7 @@ Puppet::Type.type(:l3_route).provide(:lnx) do
debug("DESTROY resource: #{@resource}")
cmd = ['--force', 'route', 'del', @property_hash[:destination], 'via', @property_hash[:gateway]]
cmd << ['metric', @property_hash[:metric]] if @property_hash[:metric] != :absent && @property_hash[:metric].to_i > 0
iproute(cmd)
self.class.iproute(cmd)
@property_hash.clear
end
@@ -127,7 +75,7 @@ Puppet::Type.type(:l3_route).provide(:lnx) do
cmd = ['route', 'change', @resource[:destination], 'via', @property_flush[:gateway]]
cmd << ['metric', @resource[:metric]] if @resource[:metric] != :absent && @resource[:metric].to_i > 0
begin
iproute(cmd)
self.class.iproute(cmd)
rescue Exception => e
if e.to_s =~ /File\s+exists/
notice("Route for '#{@resource[:destination]}' via #{@property_flush[:gateway]} already exists. Use existing...")

View File

@@ -221,6 +221,23 @@ Puppet::Type.newtype(:l23_stored_config) do
newproperty(:bond_lacp_rate)
newproperty(:bond_xmit_hash_policy)
newproperty(:bond_updelay) do
newvalues(/^\d+$/)
end
newproperty(:bond_downdelay) do
newvalues(/^\d+$/)
end
newproperty(:bond_ad_select) do
validate do |val|
allowed_values = ['0','1','2','stable','bandwidth','count']
if ! allowed_values.include? val.to_s
raise ArgumentError, "'#{val}' is not a valid bond_ad_select. Only #{allowed_values.join(', ')} allowed.)"
end
end
end
# # `:options` provides an arbitrary passthrough for provider properties, so
# # that provider specific behavior doesn't clutter up the main type but still
# # allows for more powerful actions to be taken.

View File

@@ -72,6 +72,12 @@ define l23network::l2::bond (
'active'
]
$ad_select_states = [
'stable',
'bandwidth',
'count'
]
# calculate string representation for bond_mode
if ! $bond_properties[mode] {
# default value by design https://www.kernel.org/doc/Documentation/networking/bonding.txt
@@ -82,48 +88,73 @@ define l23network::l2::bond (
$bond_mode = $bond_properties[mode]
}
# calculate string representation for lacp_rate
if $bond_mode == '802.3ad' {
if is_integer($bond_properties[lacp_rate]) and $bond_properties[lacp_rate] < size($lacp_rates) {
$lacp_rate = $lacp_rates[$bond_properties[lacp_rate]]
} else {
# default value by design https://www.kernel.org/doc/Documentation/networking/bonding.txt
$lacp_rate = pick($bond_properties[lacp_rate], $lacp_rates[0])
}
}
# calculate default miimon
if is_integer($bond_properties[miimon]) and $bond_properties[miimon] >= 0 {
$miimon = $bond_properties[miimon]
} else {
# recommended default value https://www.kernel.org/doc/Documentation/networking/bonding.txt
$miimon = 100
# init default bond properties hash
$default_bond_properties = {
mode => $bond_mode,
}
# calculate string representation for xmit_hash_policy
if ( $bond_mode == '802.3ad' or $bond_mode == 'balance-xor' or $bond_mode == 'balance-tlb') {
if ! $bond_properties[xmit_hash_policy] {
# default value by design https://www.kernel.org/doc/Documentation/networking/bonding.txt
$xmit_hash_policy = $xmit_hash_policies[0]
$default_bond_properties[xmit_hash_policy] = $xmit_hash_policies[0]
} else {
$xmit_hash_policy = $bond_properties[xmit_hash_policy]
$default_bond_properties[xmit_hash_policy] = $bond_properties[xmit_hash_policy]
}
}
if ! $bond_properties[lacp] {
# default value
$lacp = $lacp_states[0]
} else {
$lacp = $bond_properties[lacp]
# non-lacp
$default_bond_properties[xmit_hash_policy] = undef
}
# default bond properties
$default_bond_properties = {
mode => $bond_mode,
miimon => $miimon,
lacp_rate => $lacp_rate,
lacp => $lacp,
xmit_hash_policy => $xmit_hash_policy
# calculate string representation for lacp_rate
if $bond_mode == '802.3ad' or ($provider == 'ovs' and ( $bond_properties[lacp] == 'active' or $bond_properties[lacp] == 'passive')) {
if is_integer($bond_properties[lacp_rate]) and $bond_properties[lacp_rate] < size($lacp_rates) {
$default_bond_properties[lacp_rate] = $lacp_rates[$bond_properties[lacp_rate]]
} else {
# default value by design https://www.kernel.org/doc/Documentation/networking/bonding.txt
$default_bond_properties[lacp_rate] = pick($bond_properties[lacp_rate], $lacp_rates[0])
}
if $provider == 'ovs' {
$default_bond_properties[lacp] = $bond_properties[lacp]
} else {
$default_bond_properties[lacp] = undef
}
} else {
$default_bond_properties[lacp_rate] = undef
$default_bond_properties[lacp] = undef
}
# calculate default miimon
if is_integer($bond_properties[miimon]) and $bond_properties[miimon] >= 0 {
$default_bond_properties[miimon] = $bond_properties[miimon]
} else {
# recommended default value https://www.kernel.org/doc/Documentation/networking/bonding.txt
$default_bond_properties[miimon] = 100
}
# calculate default updelay
if is_integer($bond_properties[updelay]) and $bond_properties[updelay] >= 0 {
$default_bond_properties[updelay] = $bond_properties[updelay]
} else {
$default_bond_properties[updelay] = 200
}
# calculate default downdelay
if is_integer($bond_properties[downdelay]) and $bond_properties[downdelay] >= 0 {
$default_bond_properties[downdelay] = $bond_properties[downdelay]
} else {
$default_bond_properties[downdelay] = 200
}
# calculate default ad_select
if $bond_properties[ad_select] {
if is_integer($bond_properties[ad_select]) {
$default_bond_properties[ad_select] = $ad_select_states[$bond_properties[ad_select]]
} else {
$default_bond_properties[ad_select] = $bond_properties[ad_select]
}
} else {
$default_bond_properties[ad_select] = $ad_select_states[1]
}
$real_bond_properties = merge($bond_properties, $default_bond_properties)
@@ -196,6 +227,9 @@ define l23network::l2::bond (
bond_lacp => $real_bond_properties[lacp],
bond_lacp_rate => $real_bond_properties[lacp_rate],
bond_xmit_hash_policy => $real_bond_properties[xmit_hash_policy],
bond_downdelay => $real_bond_properties[downdelay],
bond_updelay => $real_bond_properties[updelay],
bond_ad_select => $real_bond_properties[ad_select],
delay_while_up => $delay_while_up,
vendor_specific => $vendor_specific,
provider => $config_provider

View File

@@ -107,13 +107,17 @@ describe 'l23network::l2::bond', :type => :define do
end
context 'Just create a lnx-bond with specific MTU' do
context 'Create a lnx-bond with specific parameters' do
let(:params) do
{
:name => 'bond0',
:interfaces => ['eth3', 'eth4'],
:mtu => 9000,
:bond_properties => {},
:bond_properties => {
'updelay' => '111',
'downdelay' => '222',
'ad_select' => '2',
},
:provider => 'lnx'
}
end
@@ -124,7 +128,10 @@ describe 'l23network::l2::bond', :type => :define do
it do
should contain_l23_stored_config('bond0').with({
'mtu' => 9000,
'mtu' => 9000,
'bond_updelay' => '111',
'bond_downdelay' => '222',
'bond_ad_select' => 'count',
})
end
@@ -211,10 +218,10 @@ describe 'l23network::l2::bond', :type => :define do
'ensure' => 'present',
'if_type' => 'bond',
'bond_mode' => 'active-backup',
'bond_lacp_rate' => nil,
'bond_xmit_hash_policy' => nil,
'bond_miimon' => '100',
})
should contain_l23_stored_config('bond0').without_bond_lacp_rate()
should contain_l23_stored_config('bond0').without_bond_xmit_hash_policy()
end
end
@@ -225,6 +232,7 @@ describe 'l23network::l2::bond', :type => :define do
:interfaces => ['eth3', 'eth4'],
:bond_properties => {
'mode' => 'balance-tlb',
'lacp' => 'active',
'lacp_rate' => 'fast',
'xmit_hash_policy' => 'layer2+3',
'miimon' => '300',
@@ -242,10 +250,11 @@ describe 'l23network::l2::bond', :type => :define do
'ensure' => 'present',
'if_type' => 'bond',
'bond_mode' => 'balance-tlb',
'bond_lacp_rate' => nil,
'bond_xmit_hash_policy' => 'layer2+3',
'bond_miimon' => '300',
})
should contain_l23_stored_config('bond0').without_bond_lacp() # because 'lacp' -- only OVS property
should contain_l23_stored_config('bond0').without_bond_lacp_rate() # because 'balance-tlb' is non-lacp mode
end
end
@@ -272,14 +281,15 @@ describe 'l23network::l2::bond', :type => :define do
end
end
context 'Create a ovs-bond with mode = balance-tlb, lacp_rate = fast xmit_hash_policy = layer2+3' do
context 'Create a ovs-bond with mode = balance-tcp, lacp_rate = fast xmit_hash_policy = layer2+3' do
let(:params) do
{
:name => 'bond-ovs',
:interfaces => ['eth2', 'eth3'],
:bridge => 'br-bond-ovs',
:bond_properties => {
'mode' => 'balance-tlb',
'mode' => 'balance-tcp',
'lacp' => 'active',
'lacp_rate' => 'fast',
'xmit_hash_policy' => 'layer2+3',
'miimon' => '300',
@@ -320,22 +330,29 @@ describe 'l23network::l2::bond', :type => :define do
'bridge' => 'br-bond-ovs',
'if_type' => 'bond',
'bond_lacp' => 'off',
'bond_mode' => 'balance-tlb',
'bond_lacp_rate' => nil,
'bond_xmit_hash_policy' => 'layer2+3',
'bond_mode' => 'balance-tcp',
'bond_lacp' => 'active',
'bond_lacp_rate' => 'fast',
'bond_miimon' => '300',
'bond_updelay' => '200',
'bond_downdelay' => '200',
'bond_ad_select' => 'bandwidth',
})
should contain_l23_stored_config('bond-ovs').without_bond_xmit_hash_policy()
end
it do
should contain_l2_bond('bond-ovs').with({
'bond_properties' => {
:mode => 'balance-tlb',
:lacp => 'off',
:lacp_rate => :undef,
:xmit_hash_policy => 'layer2+3',
:miimon => '300',
},
:mode => 'balance-tcp',
:lacp => 'active',
:lacp_rate => 'fast',
:miimon => '300',
:xmit_hash_policy => :undef,
:updelay =>"200",
:downdelay =>"200",
:ad_select =>"bandwidth",
},
})
end

View File

@@ -5,4 +5,7 @@ iface bond0 inet manual
bond-miimon 50
bond-lacp-rate fast
bond-slaves eth2 eth3
bond-xmit-hash-policy encap3+4
bond-xmit-hash-policy encap3+4
bond-updelay 111
bond-downdelay 222
bond-ad-select 2

View File

@@ -4,4 +4,4 @@ iface bond_lacp inet manual
ovs_bonds eth2 eth3
ovs_type OVSBond
ovs_bridge br0
ovs_options bond_mode=balance-tcp lacp=active other_config:lacp-time=fast other_config:bond-miimon-interval=50
ovs_options bond_mode=balance-tcp bond_updelay=111 bond_downdelay=222 lacp=active other_config:lacp-time=fast other_config:bond-miimon-interval=50

View File

@@ -18,6 +18,9 @@ describe Puppet::Type.type(:l23_stored_config).provider(:lnx_ubuntu) do
:bond_miimon => '50',
:bond_lacp_rate => 'fast',
:bond_lacp => 'passive', # used only for OVS bonds. Should do nothing for lnx.
:bond_updelay => '111',
:bond_downdelay => '222',
:bond_ad_select => '2',
:provider => "lnx_ubuntu",
},
}
@@ -74,7 +77,7 @@ describe Puppet::Type.type(:l23_stored_config).provider(:lnx_ubuntu) do
# end
# end
context "OVS bond with two interfaces" do
context "LNX bond with two interfaces" do
context 'format file' do
subject { providers[:bond0] }
@@ -86,8 +89,11 @@ describe Puppet::Type.type(:l23_stored_config).provider(:lnx_ubuntu) do
it { expect(cfg_file).to match(/bond-lacp-rate\s+fast/) }
it { expect(cfg_file).to match(/bond-mode\s+802\.3ad/) }
it { expect(cfg_file).to match(/bond-miimon\s+50/) }
it { expect(cfg_file).to match(/bond-updelay\s+111/) }
it { expect(cfg_file).to match(/bond-downdelay\s+222/) }
it { expect(cfg_file).to match(/bond-ad-select\s+2/) }
it { expect(cfg_file).to match(/bond-xmit-hash-policy\s+encap3\+4/) }
it { expect(cfg_file.split(/\n/).reject{|x| x=~/^\s*$/}.length). to eq(8) } # no more lines in the interface file
it { expect(cfg_file.split(/\n/).reject{|x| x=~/^\s*$/}.length). to eq(11) } # no more lines in the interface file
end
context "parse data from fixture" do
@@ -101,6 +107,9 @@ describe Puppet::Type.type(:l23_stored_config).provider(:lnx_ubuntu) do
it { expect(res[:bond_miimon]).to eq '50' }
it { expect(res[:bond_lacp_rate]).to eq 'fast' }
it { expect(res[:bond_lacp]).to eq nil }
it { expect(res[:bond_updelay]).to eq '111' }
it { expect(res[:bond_downdelay]).to eq '222' }
it { expect(res[:bond_ad_select]).to eq '2' }
it { expect(res[:bond_slaves]).to eq ['eth2', 'eth3'] }
it { expect(res[:bond_xmit_hash_policy]).to eq 'encap3+4' }
end

View File

@@ -18,6 +18,9 @@ describe Puppet::Type.type(:l23_stored_config).provider(:ovs_ubuntu) do
:bond_miimon => '50',
:bond_lacp_rate => 'fast',
:bond_lacp => 'active',
:bond_updelay => '111',
:bond_downdelay => '222',
:bond_ad_select => '2', # unused for OVS
:provider => "ovs_ubuntu",
},
}
@@ -89,6 +92,8 @@ describe Puppet::Type.type(:l23_stored_config).provider(:ovs_ubuntu) do
it { expect(cfg_file).to match(/ovs_options.+bond_mode=balance-tcp/) }
it { expect(cfg_file).to match(/ovs_options.+other_config:lacp-time=fast/) }
it { expect(cfg_file).to match(/ovs_options.+other_config:bond-miimon-interval=50/) }
it { expect(cfg_file).to match(/ovs_options.+bond_updelay=111/) }
it { expect(cfg_file).to match(/ovs_options.+bond_downdelay=222/) }
it { expect(cfg_file).to match(/ovs_options.+lacp=active/) }
it { expect(cfg_file.split(/\n/).reject{|x| x=~/^\s*$/}.length). to eq(7) } # no more lines in the interface file
@@ -106,6 +111,8 @@ describe Puppet::Type.type(:l23_stored_config).provider(:ovs_ubuntu) do
it { expect(res[:bond_miimon]).to eq '50' }
it { expect(res[:bond_lacp_rate]).to eq 'fast' }
it { expect(res[:bond_lacp]).to eq 'active' }
it { expect(res[:bond_updelay]).to eq '111' }
it { expect(res[:bond_downdelay]).to eq '222' }
it { expect(res[:bond_slaves]).to eq ['eth2', 'eth3'] }
end

View File

@@ -0,0 +1,76 @@
require 'spec_helper'
describe Puppet::Type.type(:l2_bond).provider(:lnx) do
let(:resource) {
Puppet::Type.type(:l2_bond).new(
:provider => :lnx,
:name => 'bond1',
:slaves => ['eth1', 'eth2'],
: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
if ENV['SPEC_PUPPET_DEBUG']
Puppet::Util::Log.level = :debug
Puppet::Util::Log.newdestination(:console)
end
provider.class.stubs(:iproute).with('addr', 'flush', 'dev', 'eth1').returns(true)
provider.class.stubs(:iproute).with('addr', 'flush', 'dev', 'eth2').returns(true)
end
it "Just create bond, which unify two NICs" do
provider.create
#provider.flush
end
it "Create bond and setup required properties" do
provider.class.stubs(:set_sys_class).with('/sys/class/net/bonding_masters', '+bond1').returns(true)
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(: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)
provider.class.stubs(:get_sys_class).with('/sys/class/net/bond1/bonding/lacp_rate').returns('slow')
provider.class.stubs(:set_sys_class).with('/sys/class/net/bond1/bonding/lacp_rate', 'fast').returns(true)
provider.class.stubs(:get_sys_class).with('/sys/class/net/bond1/bonding/ad_select').returns('stable')
provider.class.stubs(:set_sys_class).with('/sys/class/net/bond1/bonding/ad_select', '2').returns(true)
provider.class.stubs(:get_sys_class).with('/sys/class/net/bond1/bonding/updelay').returns('0')
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.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/ }
provider.flush
end
it "Delete existing bond" do
provider.class.stubs(:set_sys_class).with('/sys/class/net/bonding_masters', '-bond1').returns(true)
provider.destroy
end
end
end

View File

@@ -9,9 +9,10 @@ describe Puppet::Type.type(:l2_bond).provider(:ovs) do
:bridge => 'br1',
:slaves => ['eth1', 'eth2'],
:bond_properties => {
'mode' => 'balance-slb',
'lacp_rate' => 'fast',
#'xmit_hash_policy' => 'layer2',
'mode' => 'balance-slb',
'lacp_rate' => 'fast',
'updelay' => 111,
'downdelay' => 222,
},
)
}
@@ -35,6 +36,8 @@ describe Puppet::Type.type(:l2_bond).provider(:ovs) do
it "Create bond and setup required properties" do
provider.class.expects(:vsctl).with('--', 'set', 'Port', 'bond1', 'bond_mode=balance-slb').returns(true)
provider.class.expects(:vsctl).with('--', 'set', 'Port', 'bond1', 'other_config:lacp_time=fast').returns(true)
provider.class.expects(:vsctl).with('--', 'set', 'Port', 'bond1', 'bond_updelay=111').returns(true)
provider.class.expects(:vsctl).with('--', 'set', 'Port', 'bond1', 'bond_downdelay=222').returns(true)
provider.create
provider.expects(:warn).with { |arg| arg =~ /OVS\s+don't\s+allow\s+change\s+bond\s+slaves/ }
provider.flush

View File

@@ -18,20 +18,20 @@ describe Puppet::Type.type(:l3_ifconfig).provider(:lnx) do
describe "l3_ifconfig " do
before(:each) do
provider.class.stubs(:arping).with('-U', '-c 32', '-w 5', '-I', 'eth1', '10.99.1.4').returns(true)
provider.class.stubs(:arping).with(['-A', '-c 32', '-w 2', '-I', 'eth1', '10.99.1.4']).returns(true)
provider.class.stubs(:iproute)
provider.class.stubs(:iproute).with(['route', 'del', 'default', 'dev', 'eth1']).raises(Puppet::ExecutionFailure)
end
it "Assign IP address to the NIC" do
provider.class.stubs(:arping).with('-D', '-c 32', '-w 5', '-I', 'eth1', '10.99.1.4').returns(true)
provider.class.stubs(:arping).with(['-D', '-f', '-c 32', '-w 2', '-I', 'eth1', '10.99.1.4']).returns(true)
provider.expects(:warn).with { |arg| arg =~ /IP\s+duplication/ }.never
provider.create
provider.flush
end
it "Assign duplication IP address to the NIC" do
provider.class.stubs(:arping).with('-D', '-c 32', '-w 5', '-I', 'eth1', '10.99.1.4').raises(Exception, """
provider.class.stubs(:arping).with(['-D', '-f', '-c 32', '-w 2', '-I', 'eth1', '10.99.1.4']).raises(Exception, """
ARPING 10.99.1.4 from 0.0.0.0 eth1
Unicast reply from 10.99.1.4 [00:1C:42:99:06:98] 1.292ms
Sent 1 probes (1 broadcast(s))
@@ -43,7 +43,7 @@ Received 1 response(s)
end
it "Arping execution error while assigning IP address to the NIC" do
provider.class.stubs(:arping).with('-D', '-c 32', '-w 5', '-I', 'eth1', '10.99.1.4').raises(Puppet::ExecutionFailure, '')
provider.class.stubs(:arping).with(['-D', '-f', '-c 32', '-w 2', '-I', 'eth1', '10.99.1.4']).raises(Puppet::ExecutionFailure, '')
provider.create
expect{provider.flush}.to raise_error(Puppet::ExecutionFailure)
end