Merge "Lnx2Lnx patchcord implementation for ubuntu"

This commit is contained in:
Jenkins 2015-11-28 22:12:01 +00:00 committed by Gerrit Code Review
commit b9f8c28f0e
17 changed files with 550 additions and 39 deletions

View File

@ -5,6 +5,7 @@ class Puppet::Provider::InterfaceToolset < Puppet::Provider
def self.iproute(*cmd) def self.iproute(*cmd)
actual_cmd = ['ip'] + Array(*cmd) actual_cmd = ['ip'] + Array(*cmd)
debug("iproute: run the command #{actual_cmd.join(' ')}")
rv = [] rv = []
IO.popen(actual_cmd.join(' ') + ' 2>&1') do |ff| IO.popen(actual_cmd.join(' ') + ' 2>&1') do |ff|
rv = ff.readlines().map{|l| l.chomp()} rv = ff.readlines().map{|l| l.chomp()}
@ -29,6 +30,33 @@ class Puppet::Provider::InterfaceToolset < Puppet::Provider
return rv return rv
end end
def self.brctl(*cmd)
actual_cmd = ['brctl'] + 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.ethtool(*cmd)
actual_cmd = ['ethtool'] + Array(*cmd)
rv = []
debug(actual_cmd.join(' ') + ' 2>&1')
IO.popen(actual_cmd.join(' ') + ' 2>&1') do |ff|
rv = ff.readlines().map{|l| l.chomp()}
ff.close
if 0 != $?.exitstatus and 94 != $?.exitstatus # 94 is a 'no stats available'. it's a not error.
rv = nil
end
end
return rv
end
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
def self.iface_exist?(iface) def self.iface_exist?(iface)
@ -71,6 +99,21 @@ class Puppet::Provider::InterfaceToolset < Puppet::Provider
end end
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
def self.get_iface_peer_index(iface)
# returns:
# N -- ifindex of peer interface
# nil -- interface in not an veth pair jack
cmd = ['-S', iface]
begin
rv = ethtool(cmd)
rescue Exception => e
debug("Non-fatal-Error: Can't run ethtool for interface '#{iface}': #{e.message}")
return nil
end
rv = rv.select{|l| l =~ /\s*peer_ifindex\:\s+\d+/}[0]
(rv.nil? ? nil : rv.split(':')[-1].strip.to_i)
end
def self.get_iface_state(iface) def self.get_iface_state(iface)
# returns: # returns:
# true -- interface in UP state # true -- interface in UP state

View File

@ -78,6 +78,11 @@ class Puppet::Provider::L23_stored_config_ubuntu < Puppet::Provider::L23_stored_
:detect_re => /(post-)?up\s+sleep\s+(\d+)/, :detect_re => /(post-)?up\s+sleep\s+(\d+)/,
:detect_shift => 2, :detect_shift => 2,
}, },
:jacks => {
# pre-up ip link add p_33470efd-0 type veth peer name p_33470efd-1
:detect_re => /pre-up\s+ip\s+link\s+add\s+([\w\-]+)\s+type\s+veth\s+peer\s+name\s+([\w\-]+)/,
:detect_shift => 1,
},
} }
end end
def collected_properties def collected_properties
@ -200,15 +205,18 @@ class Puppet::Provider::L23_stored_config_ubuntu < Puppet::Provider::L23_stored_
# # todo(sv): Make more powerful methodology for recognizind Bridges. # # todo(sv): Make more powerful methodology for recognizind Bridges.
# hash['if_type'] = :bridge # hash['if_type'] = :bridge
# end # end
when /bridge-ports/ when /bridge[-_]ports/
hash['if_type'] = :bridge hash['if_type'] = :bridge
hash[key] = val hash[key] = val
when /bond-(slaves|mode)/ when /bond[-_](slaves|mode)/
hash['if_type'] = :bond hash['if_type'] = :bond
hash[key] = val hash[key] = val
else else
hash[key] = val hash[key] = val
end end
if val =~ /\s+type\s+veth\s+/
hash['if_type'] = :patch
end
else else
raise Puppet::Error, %{#{filename} is malformed; "#{line}" did not match "#{pair_regex.to_s}"} raise Puppet::Error, %{#{filename} is malformed; "#{line}" did not match "#{pair_regex.to_s}"}
end end
@ -382,6 +390,10 @@ class Puppet::Provider::L23_stored_config_ubuntu < Puppet::Provider::L23_stored_
return rv return rv
end end
def self.mangle__jacks(data)
[data[0][0], data[0][1]]
end
### ###
# Hash to file # Hash to file
@ -420,7 +432,7 @@ class Puppet::Provider::L23_stored_config_ubuntu < Puppet::Provider::L23_stored_
#add to content unmangled collected-properties #add to content unmangled collected-properties
collected_properties.keys.each do |type_name| collected_properties.keys.each do |type_name|
data = provider.send(type_name) data = provider.send(type_name)
if ((!data.nil? or !data.empty?) and data.to_s != 'absent') if ! ['', 'absent'].include? data.to_s
mangle_method_name="unmangle__#{type_name}" mangle_method_name="unmangle__#{type_name}"
if self.respond_to?(mangle_method_name) if self.respond_to?(mangle_method_name)
rv = self.send(mangle_method_name, provider, data) rv = self.send(mangle_method_name, provider, data)
@ -556,5 +568,12 @@ class Puppet::Provider::L23_stored_config_ubuntu < Puppet::Provider::L23_stored_
return rv return rv
end end
def self.unmangle__jacks(provider, data)
rv = []
rv << "pre-up ip link add #{data[0]} type veth peer name #{data[1]}"
rv << "post-up ip link set up dev #{data[1]}"
rv << "post-down ip link del #{data[0]}"
end
end end
# vim: set ts=2 sw=2 et : # vim: set ts=2 sw=2 et :

View File

@ -60,11 +60,17 @@ class Puppet::Provider::L2_base < Puppet::Provider::InterfaceToolset
:port_type => [], :port_type => [],
:onboot => self.get_iface_state(if_name), :onboot => self.get_iface_state(if_name),
:ethtool => nil, :ethtool => nil,
:peer_ifindex => nil,
:ifindex => File.open("#{if_dir}/ifindex").read.chomp.to_i,
:mtu => File.open("#{if_dir}/mtu").read.chomp.to_i, :mtu => File.open("#{if_dir}/mtu").read.chomp.to_i,
:provider => (if_name == 'ovs-system') ? 'ovs' : 'lnx' , :provider => (if_name == 'ovs-system') ? 'ovs' : 'lnx' ,
} }
# determine port_type for this iface # determine port_type for this iface
if File.directory? "#{if_dir}/bonding" peer_ifindex = self.get_iface_peer_index(if_name)
if !peer_ifindex.nil?
port[if_name][:port_type] << 'jack' << 'unremovable'
port[if_name][:peer_ifindex] = peer_ifindex
elsif File.directory? "#{if_dir}/bonding"
# This interface is a baster of bond, get bonding properties # This interface is a baster of bond, get bonding properties
port[if_name][:slaves] = File.open("#{if_dir}/bonding/slaves").read.chomp.strip.split(/\s+/).sort port[if_name][:slaves] = File.open("#{if_dir}/bonding/slaves").read.chomp.strip.split(/\s+/).sort
port[if_name][:port_type] << 'bond' << 'unremovable' port[if_name][:port_type] << 'bond' << 'unremovable'
@ -365,7 +371,7 @@ class Puppet::Provider::L2_base < Puppet::Provider::InterfaceToolset
re_c = /([\w\-]+)\s+\d+/ re_c = /([\w\-]+)\s+\d+/
begin begin
# todo(sv): using port_list instead fork subprocess # todo(sv): using port_list instead fork subprocess
brctl('show').split(/\n+/).select{|l| l.match(re_c)}.collect{|a| $1 if a.match(re_c)}.each do |br_name| self.brctl(['show']).select{|l| l.match(re_c)}.collect{|a| $1 if a.match(re_c)}.each do |br_name|
br_name.strip! br_name.strip!
bridges[br_name] = { bridges[br_name] = {
:stp => (File.open("/sys/class/net/#{br_name}/bridge/stp_state").read.strip.to_i == 1), :stp => (File.open("/sys/class/net/#{br_name}/bridge/stp_state").read.strip.to_i == 1),
@ -421,7 +427,7 @@ class Puppet::Provider::L2_base < Puppet::Provider::InterfaceToolset
# (lnx and ovs (with type internal)) included to the lnx bridge # (lnx and ovs (with type internal)) included to the lnx bridge
# #
begin begin
brctl_show = brctl('show').split(/\n+/).select{|l| l.match(/^[\w\-]+\s+\d+/) or l.match(/^\s+[\w\.\-]+/)} brctl_show = self.brctl(['show']).split(/\n+/).select{|l| l.match(/^[\w\-]+\s+\d+/) or l.match(/^\s+[\w\.\-]+/)}
rescue rescue
debug("No LNX bridges found, because error while 'brctl show' execution") debug("No LNX bridges found, because error while 'brctl show' execution")
return {} return {}

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 Puppet::Type.type(:l2_bond).provide(:lnx, :parent => Puppet::Provider::Lnx_base) do
defaultfor :osfamily => :linux defaultfor :osfamily => :linux
commands :ethtool_cmd => 'ethtool', commands :ethtool_cmd => 'ethtool'
:brctl => 'brctl'
def self.prefetch(resources) def self.prefetch(resources)
@ -192,7 +191,7 @@ Puppet::Type.type(:l2_bond).provide(:lnx, :parent => Puppet::Provider::Lnx_base)
ovs_vsctl(['del-port', br_name, @resource[:bond]]) ovs_vsctl(['del-port', br_name, @resource[:bond]])
# todo catch exception # todo catch exception
when :lnx when :lnx
brctl('delif', br_name, @resource[:bond]) self.class.brctl(['delif', br_name, @resource[:bond]])
# todo catch exception # todo catch exception
else else
#pass #pass
@ -205,7 +204,7 @@ Puppet::Type.type(:l2_bond).provide(:lnx, :parent => Puppet::Provider::Lnx_base)
when :ovs when :ovs
ovs_vsctl(['add-port', @property_flush[:bridge], @resource[:bond]]) ovs_vsctl(['add-port', @property_flush[:bridge], @resource[:bond]])
when :lnx when :lnx
brctl('addif', @property_flush[:bridge], @resource[:bond]) self.class.brctl(['addif', @property_flush[:bridge], @resource[:bond]])
else else
#pass #pass
end end

View File

@ -8,8 +8,7 @@ require File.join(File.dirname(__FILE__), '..','..','..','puppet/provider/lnx_ba
Puppet::Type.type(:l2_bridge).provide(:lnx, :parent => Puppet::Provider::Lnx_base) do Puppet::Type.type(:l2_bridge).provide(:lnx, :parent => Puppet::Provider::Lnx_base) do
defaultfor :osfamily => :linux defaultfor :osfamily => :linux
commands :brctl => 'brctl', commands :ethtool_cmd => 'ethtool'
:ethtool_cmd => 'ethtool'
def self.instances def self.instances
rv = [] rv = []
@ -37,7 +36,7 @@ Puppet::Type.type(:l2_bridge).provide(:lnx, :parent => Puppet::Provider::Lnx_bas
@old_property_hash = {} @old_property_hash = {}
@property_flush = {}.merge! @resource @property_flush = {}.merge! @resource
begin begin
brctl('addbr', @resource[:bridge]) self.class.brctl(['addbr', @resource[:bridge]])
rescue rescue
# Some time interface may be created by OS init scripts. It's a normal for Ubuntu. # Some time interface may be created by OS init scripts. It's a normal for Ubuntu.
raise if ! self.class.iface_exist? @resource[:bridge] raise if ! self.class.iface_exist? @resource[:bridge]
@ -48,7 +47,7 @@ Puppet::Type.type(:l2_bridge).provide(:lnx, :parent => Puppet::Provider::Lnx_bas
def destroy def destroy
self.class.interface_down(@resource[:bridge]) self.class.interface_down(@resource[:bridge])
brctl('delbr', @resource[:bridge]) self.class.brctl(['delbr', @resource[:bridge]])
end end
def flush def flush

View File

@ -2,8 +2,7 @@ require File.join(File.dirname(__FILE__), '..','..','..','puppet/provider/ovs_ba
Puppet::Type.type(:l2_bridge).provide(:ovs, :parent => Puppet::Provider::Ovs_base) do Puppet::Type.type(:l2_bridge).provide(:ovs, :parent => Puppet::Provider::Ovs_base) do
commands :vsctl => 'ovs-vsctl', commands :vsctl => 'ovs-vsctl',
:ethtool_cmd => 'ethtool', :ethtool_cmd => 'ethtool'
:brctl => 'brctl'
def self.skip_port_for?(port_props) def self.skip_port_for?(port_props)
port_props[:br_type] != 'ovs' port_props[:br_type] != 'ovs'

View File

@ -0,0 +1,141 @@
require File.join(File.dirname(__FILE__), '..','..','..','puppet/provider/lnx_base')
Puppet::Type.type(:l2_patch).provide(:lnx, :parent => Puppet::Provider::Lnx_base) do
defaultfor :osfamily => :linux
def self.instances
ports = get_lnx_ports()
jacks = []
ports.each_pair do |if_name, if_props|
next unless if_props[:port_type].include? 'jack'
jacks << {
:name => if_name,
:bridge => if_props[:bridge],
:ifindex => if_props[:ifindex],
:peer_ifindex => if_props[:peer_ifindex],
:mtu => if_props[:mtu],
:provider => 'lnx'
}
end
# search pairs of jacks and make patchcord resources
patches = []
skip = []
mtu = nil
jacks.each do |jack|
next if skip.include? jack[:name]
# process patch between two bridges
found_peer = jacks.select{|j| j[:ifindex]==jack[:peer_ifindex]}
next if found_peer.empty?
peer = found_peer[0]
_bridges = [jack[:bridge], peer[:bridge]].sort
_tails = ([jack[:bridge], peer[:bridge]] == _bridges ? [jack[:name], peer[:name]] : [peer[:name], jack[:name]])
if _bridges.include? nil
_name = "patch__raw__#{_tails[0]}--#{_tails[1]}"
else
_name = L23network.get_patch_name([jack[:bridge],peer[:bridge]])
end
props = {
:ensure => :present,
:name => _name,
:bridges => _bridges,
:jacks => _tails,
:mtu => mtu.to_s,
:vlan_ids => ['0','0'], # because veth pairs can't be tagged
:provider => 'ovs'
}
debug("PREFETCH properties for '#{props[:name]}': #{props}")
patches << new(props)
skip << peer[:name]
end
return patches
end
def create
debug("CREATE resource: #{@resource}")
@old_property_hash = {}
@property_flush = {}.merge! @resource
patch_name = L23network.get_patch_name(@resource[:jacks])
begin
self.class.iproute(['link', 'add', 'dev', @resource[:jacks][0], 'type', 'veth', 'peer', 'name', @resource[:jacks][1]])
rescue
# Some time interface may be created by OS init scripts.
raise unless self.class.iface_exist?(@resource[:jacks][0]) & self.class.iface_exist?(@resource[:jacks][1])
notice("'#{patch_name}' is already created by ghost event.")
end
# plug-in jacks to bridges
_bridges = self.class.get_bridge_list()
self.class.get_bridges_order_for_patch(@resource[:bridges]).each_with_index do |br_name, i|
_br = _bridges.fetch(br_name, {})
#todo: sv: re-design for call method from bridge provider
if _br[:br_type].to_s == 'lnx'
self.class.iproute(['link', 'set', 'dev', @resource[:jacks][i], 'master', br_name ])
elsif _br[:br_type].to_s == 'ovs'
fail("lnx2ovs patchcord '#{patch_name}' is not implemented yet, use ovs2lnx for this purpose!")
#self.class.ovs_vsctl(['--may-exist', 'add-port', br_name, @resource[:jacks][i]])
end
end
# UP jacks
@resource[:jacks].each do |jack_name|
self.class.interface_up(jack_name, true)
end
end
def destroy
debug("DESTROY resource: #{@resource}")
self.class.iproute(['link', 'del', 'dev', @resource[:jacks][0]])
end
def flush
if !@property_flush.empty?
debug("FLUSH properties: #{@property_flush}")
if !['', 'absent'].include? @property_flush[:mtu].to_s
# 'absent' is a synonym 'do-not-touch' for MTU
@property_hash[:jacks].uniq.each do |iface|
self.class.set_mtu(iface, @property_flush[:mtu])
end
end
#todo: /sv: make ability of change bridges for RAW patchcords
@property_hash = resource.to_hash
end
end
#-----------------------------------------------------------------
def bridges
self.class.get_bridges_order_for_patch(@property_hash[:bridges])
end
def bridges=(val)
@property_flush[:bridges] = self.class.get_bridges_order_for_patch(val)
end
def vlan_ids
['0', '0']
end
def vlan_ids=(val)
warn("There are no ability for setup VLAN IDs for LNX-patchcords")
end
def mtu
'absent'
end
def mtu=(val)
@property_flush[:mtu] = val
end
def jacks
@property_hash[:jacks]
end
def jacks=(val)
nil
end
def cross
nil
end
def cross=(val)
nil
end
end
# vim: set ts=2 sw=2 et :

View File

@ -3,8 +3,7 @@ require File.join(File.dirname(__FILE__), '..','..','..','puppet/provider/ovs_ba
Puppet::Type.type(:l2_patch).provide(:ovs, :parent => Puppet::Provider::Ovs_base) do Puppet::Type.type(:l2_patch).provide(:ovs, :parent => Puppet::Provider::Ovs_base) do
commands :vsctl => 'ovs-vsctl', commands :vsctl => 'ovs-vsctl',
:ethtool_cmd => 'ethtool', :ethtool_cmd => 'ethtool'
:brctl => 'brctl'
def self.get_instances(big_hash) def self.get_instances(big_hash)
big_hash.fetch(:port, {}) big_hash.fetch(:port, {})
@ -57,7 +56,7 @@ Puppet::Type.type(:l2_patch).provide(:ovs, :parent => Puppet::Provider::Ovs_base
peer = found_peer[0] peer = found_peer[0]
_bridges = [jack[:bridge], peer[:bridge]].sort _bridges = [jack[:bridge], peer[:bridge]].sort
_tails = ([jack[:bridge], peer[:bridge]] == _bridges ? [jack[:name], peer[:name]] : [peer[:name], jack[:name]]) _tails = ([jack[:bridge], peer[:bridge]] == _bridges ? [jack[:name], peer[:name]] : [peer[:name], jack[:name]])
_vlan_ids = [(jack[:vlan_id].to_i or 0), (peer[:vlan_id].to_i or 0)] _vlan_ids = [jack[:vlan_id].to_i, peer[:vlan_id].to_i]
end end
props = { props = {
:ensure => :present, :ensure => :present,
@ -95,12 +94,12 @@ Puppet::Type.type(:l2_patch).provide(:ovs, :parent => Puppet::Provider::Ovs_base
vsctl('--may-exist', 'add-port', bridges[0], jack, '--', 'set', 'Interface', jack, 'type=internal') vsctl('--may-exist', 'add-port', bridges[0], jack, '--', 'set', 'Interface', jack, 'type=internal')
if lnx_port_br_mapping.has_key? jack and lnx_port_br_mapping[jack][:bridge] != bridges[1] if lnx_port_br_mapping.has_key? jack and lnx_port_br_mapping[jack][:bridge] != bridges[1]
# eject lnx-side jack from bridge, if jack aldeady a member # eject lnx-side jack from bridge, if jack aldeady a member
brctl('delif', lnx_port_br_mapping[jack][:bridge], jack) self.brctl(['delif', lnx_port_br_mapping[jack][:bridge], jack])
lnx_port_br_mapping.delete(jack) lnx_port_br_mapping.delete(jack)
end end
if !lnx_port_br_mapping.has_key? jack if !lnx_port_br_mapping.has_key? jack
begin begin
brctl('addif', bridges[1], jack) self.class.brctl(['addif', bridges[1], jack])
rescue Exception => e rescue Exception => e
if e.to_s =~ /device\s+#{jack}\s+is\s+already\s+a\s+member\s+of\s+a\s+bridge/ if e.to_s =~ /device\s+#{jack}\s+is\s+already\s+a\s+member\s+of\s+a\s+bridge/
notice("'#{jack}' already addeded to '#{bridges[1]}' by ghost event.") notice("'#{jack}' already addeded to '#{bridges[1]}' by ghost event.")
@ -138,7 +137,7 @@ debug(cmds)
jack = L23network.get_jack_name(@resource[:bridges], 0) jack = L23network.get_jack_name(@resource[:bridges], 0)
# we don't normalize bridge ordering, because OVS bridge always first. by design. # we don't normalize bridge ordering, because OVS bridge always first. by design.
if File.symlink?("/sys/class/net/#{@resource[:bridges][1]}/brif/#{jack}") if File.symlink?("/sys/class/net/#{@resource[:bridges][1]}/brif/#{jack}")
brctl('delif', @resource[:bridges][1], jack) self.class.brctl(['delif', @resource[:bridges][1], jack])
end end
vsctl('del-port', @resource[:bridges][0], jack) vsctl('del-port', @resource[:bridges][0], jack)
else else
@ -207,6 +206,13 @@ debug(cmds)
@property_flush[:vlan_ids] = val @property_flush[:vlan_ids] = val
end end
def mtu
'absent'
end
def mtu=(val)
@property_flush[:mtu] = val
end
def jacks def jacks
@property_hash[:jacks] @property_hash[:jacks]
end end

View File

@ -3,7 +3,6 @@ require File.join(File.dirname(__FILE__), '..','..','..','puppet/provider/lnx_ba
Puppet::Type.type(:l2_port).provide(:lnx, :parent => Puppet::Provider::Lnx_base) do Puppet::Type.type(:l2_port).provide(:lnx, :parent => Puppet::Provider::Lnx_base) do
defaultfor :osfamily => :linux defaultfor :osfamily => :linux
commands :ethtool_cmd => 'ethtool', commands :ethtool_cmd => 'ethtool',
:brctl => 'brctl',
:pkill => 'pkill' :pkill => 'pkill'
@ -124,7 +123,7 @@ Puppet::Type.type(:l2_port).provide(:lnx, :parent => Puppet::Provider::Lnx_base)
when :ovs when :ovs
self.class.ovs_vsctl(['del-port', br_name, @resource[:interface]]) self.class.ovs_vsctl(['del-port', br_name, @resource[:interface]])
when :lnx when :lnx
brctl('delif', br_name, @resource[:interface]) self.class.brctl(['delif', br_name, @resource[:interface]])
else else
#pass #pass
end end
@ -137,7 +136,7 @@ Puppet::Type.type(:l2_port).provide(:lnx, :parent => Puppet::Provider::Lnx_base)
self.class.ovs_vsctl(['add-port', @property_flush[:bridge], @resource[:interface]]) self.class.ovs_vsctl(['add-port', @property_flush[:bridge], @resource[:interface]])
when :lnx when :lnx
begin begin
brctl('addif', @property_flush[:bridge], @resource[:interface]) self.class.brctl(['addif', @property_flush[:bridge], @resource[:interface]])
rescue rescue
# Sometimes interface may be automatically added to bridge if config file exists before interface creation, # Sometimes interface may be automatically added to bridge if config file exists before interface creation,
# especially vlan interfaces. It appears on CentOS. # especially vlan interfaces. It appears on CentOS.

View File

@ -48,6 +48,7 @@ define l23network::l2::patch (
$act_bridges = [$bridges[1], $bridges[0]] $act_bridges = [$bridges[1], $bridges[0]]
$act_vlan_ids = undef $act_vlan_ids = undef
} else { } else {
$lnx2lnx = true
$act_bridges = $bridges $act_bridges = $bridges
} }
@ -91,7 +92,36 @@ define l23network::l2::patch (
provider => $config_provider provider => $config_provider
} }
L23_stored_config[$patch_jacks_names[1]] -> L2_patch[$patch_name] L23_stored_config[$patch_jacks_names[1]] -> L2_patch[$patch_name]
} elsif $lnx2lnx {
if ! defined(L23_stored_config[$patch_jacks_names[0]]) {
l23_stored_config { $patch_jacks_names[0]: }
}
L23_stored_config <| title == $patch_jacks_names[0] |> {
ensure => $ensure,
if_type => 'patch',
bridge => $act_bridges[0],
jacks => $patch_jacks_names,
onboot => true,
vendor_specific => $vendor_specific,
provider => $config_provider
}
L23_stored_config[$patch_jacks_names[0]] -> L2_patch[$patch_name]
if ! defined(L23_stored_config[$patch_jacks_names[1]]) {
l23_stored_config { $patch_jacks_names[1]: }
}
L23_stored_config <| title == $patch_jacks_names[1] |> {
ensure => $ensure,
if_type => 'patch',
bridge => $act_bridges[1],
jacks => $patch_jacks_names,
onboot => true,
vendor_specific => $vendor_specific,
provider => $config_provider
}
L23_stored_config[$patch_jacks_names[1]] -> L2_patch[$patch_name]
} else { } else {
# ovs2lnx patch
if ! defined(L23_stored_config[$patch_jacks_names[0]]) { if ! defined(L23_stored_config[$patch_jacks_names[0]]) {
# we use only one (first) patch jack name here and later, # we use only one (first) patch jack name here and later,
# because a both jacks for patch are created by # because a both jacks for patch are created by

View File

@ -0,0 +1,4 @@
auto br1
iface br1 inet static
bridge_ports p_33470efd-0
address 192.168.88.2/24

View File

@ -0,0 +1,4 @@
auto br2
iface br2 inet static
bridge_ports p_33470efd-1
address 192.168.99.2/24

View File

@ -0,0 +1,5 @@
auto p_33470efd-0
iface p_33470efd-0 inet manual
pre-up ip link add p_33470efd-0 type veth peer name p_33470efd-1
post-up ip link set up dev p_33470efd-1
post-down ip link del p_33470efd-0

View File

@ -0,0 +1,5 @@
auto p_33470efd-1
iface p_33470efd-1 inet manual
pre-up ip link add p_33470efd-0 type veth peer name p_33470efd-1
post-up ip link set up dev p_33470efd-1
post-down ip link del p_33470efd-0

View File

@ -0,0 +1,173 @@
require 'spec_helper'
resources_map = {
:'br1' => {
:name => "br1",
:onboot => "yes",
:method => "static",
:if_type => "bridge",
:ipaddr => "192.168.88.2/24",
:bridge_ports => ['p_33470efd-0'], # in real cases this value doesn't pass directly to stored_config,
:provider => "lnx_ubuntu", # but filled in generate() method of type
},
:'br2' => {
:name => "br2",
:onboot => "yes",
:method => "static",
:if_type => "bridge",
:ipaddr => "192.168.99.2/24",
:bridge_ports => ['p_33470efd-1'], # in real cases this value doesn't pass directly to stored_config,
:provider => "lnx_ubuntu", # but filled in generate() method of type
},
:'p_33470efd-0' => {
:name => 'p_33470efd-0',
:if_type => 'patch',
:bridge => ["br1"],
:jacks => ['p_33470efd-0', 'p_33470efd-1'],
:provider => "lnx_ubuntu",
},
:'p_33470efd-1' => {
:name => "p_33470efd-1",
:if_type => 'patch',
:bridge => ["br2"],
:jacks => ['p_33470efd-0', 'p_33470efd-1'],
:provider => "lnx_ubuntu",
},
}
# This test is functional continue of .spec/classes/ovs2lnx_patch__spec.rb
describe Puppet::Type.type(:l23_stored_config).provider(:lnx_ubuntu) do
let(:input_data) { resources_map}
let(:resources) do
resources = {}
input_data.each do |name, res|
resources.store name, Puppet::Type.type(:l23_stored_config).new(res)
end
return resources
end
let(:providers) do
providers = {}
resources.each do |name, resource|
provider = resource.provider
if ENV['SPEC_PUPPET_DEBUG']
class << provider
def debug(msg)
puts msg
end
end
end
provider.create
providers.store name, provider
end
return providers
end
before(:each) do
puppet_debug_override()
end
def fixture_path
File.join(PROJECT_ROOT, 'spec', 'fixtures', 'provider', 'l23_stored_config', 'lnx_ubuntu__lnx2lnx_patch__spec')
end
def fixture_file(file)
File.join(fixture_path, file)
end
def fixture_data(file)
File.read(fixture_file(file))
end
context "when formating config files" do
context 'for LNX bridge br1' do
subject { providers[:'br1'] }
let(:cfg_file) { subject.class.format_file('filepath', [subject]) }
it { expect(cfg_file).to match(/auto\s+br1/) }
it { expect(cfg_file).to match(/iface\s+br1\s+inet\s+static/) }
it { expect(cfg_file).to match(/bridge_ports\s+p_33470efd-0/) }
it { expect(cfg_file).to match(/address\s+192.168.88.2\/24/) }
it { expect(cfg_file.split(/\n/).reject{|x| x=~/^\s*$/}.length). to eq(4) }
end
context 'for LNX bridge br2' do
subject { providers[:'br2'] }
let(:cfg_file) { subject.class.format_file('filepath', [subject]) }
it { expect(cfg_file).to match(/auto\s+br2/) }
it { expect(cfg_file).to match(/iface\s+br2\s+inet\s+static/) }
it { expect(cfg_file).to match(/bridge_ports\s+p_33470efd-1/) }
it { expect(cfg_file).to match(/address\s+192.168.99.2\/24/) }
it { expect(cfg_file.split(/\n/).reject{|x| x=~/^\s*$/}.length). to eq(4) }
end
context 'for lnx2lnx patchcord p_33470efd-0' do
subject { providers[:'p_33470efd-0'] }
let(:cfg_file) { subject.class.format_file('filepath', [subject]) }
it { expect(cfg_file).to match(/auto\s+p_33470efd-0/) }
it { expect(cfg_file).to match(/iface\s+p_33470efd-0\s+inet\s+manual/) }
it { expect(cfg_file).to match(/pre-up\s+ip\s+link\s+add\s+p_33470efd-0\s+type\s+veth\s+peer\s+name\s+p_33470efd-1/) }
it { expect(cfg_file).to match(/post-up\s+ip\s+link\s+set\s+up\s+dev\s+p_33470efd-1/) }
it { expect(cfg_file).to match(/post-down\s+ip\s+link\s+del\s+p_33470efd-0/) }
it { expect(cfg_file.split(/\n/).reject{|x| x=~/^\s*$/}.length). to eq(5) }
end
context 'for lnx2lnx patchcord p_33470efd-1' do
subject { providers[:'p_33470efd-1'] }
let(:cfg_file) { subject.class.format_file('filepath', [subject]) }
it { expect(cfg_file).to match(/auto\s+p_33470efd-1/) }
it { expect(cfg_file).to match(/iface\s+p_33470efd-1\s+inet\s+manual/) }
it { expect(cfg_file).to match(/pre-up\s+ip\s+link\s+add\s+p_33470efd-0\s+type\s+veth\s+peer\s+name\s+p_33470efd-1/) }
it { expect(cfg_file).to match(/post-up\s+ip\s+link\s+set\s+up\s+dev\s+p_33470efd-1/) }
it { expect(cfg_file).to match(/post-down\s+ip\s+link\s+del\s+p_33470efd-0/) }
it { expect(cfg_file.split(/\n/).reject{|x| x=~/^\s*$/}.length). to eq(5) }
end
end
context "when parsing config files" do
context 'for LNX bridge br1' do
let(:res) { subject.class.parse_file('br1', fixture_data('ifcfg-br1'))[0] }
it { expect(res[:method]).to eq :static }
it { expect(res[:onboot]).to eq true }
it { expect(res[:name]).to eq 'br1' }
it { expect(res[:bridge_ports]).to eq ['p_33470efd-0'] }
it { expect(res[:if_type].to_s).to eq 'bridge' }
it { expect(res[:if_provider].to_s).to eq 'lnx' }
end
context 'for LNX bridge br2' do
let(:res) { subject.class.parse_file('br2', fixture_data('ifcfg-br2'))[0] }
it { expect(res[:method]).to eq :static }
it { expect(res[:onboot]).to eq true }
it { expect(res[:name]).to eq 'br2' }
it { expect(res[:bridge_ports]).to eq ['p_33470efd-1'] }
it { expect(res[:if_type].to_s).to eq 'bridge' }
it { expect(res[:if_provider].to_s).to eq 'lnx' }
end
context 'for lnx2lnx patchcord p_33470efd-0' do
let(:res) { subject.class.parse_file('p_33470efd-0', fixture_data('ifcfg-p_33470efd-0'))[0] }
it { expect(res[:method]).to eq :manual }
it { expect(res[:onboot]).to eq true }
it { expect(res[:name]).to eq 'p_33470efd-0' }
it { expect(res[:if_type].to_s).to eq 'patch' }
it { expect(res[:if_provider].to_s).to eq 'lnx' }
end
context 'for lnx2lnx patchcord p_33470efd-1' do
let(:res) { subject.class.parse_file('p_33470efd-1', fixture_data('ifcfg-p_33470efd-1'))[0] }
it { expect(res[:method]).to eq :manual }
it { expect(res[:onboot]).to eq true }
it { expect(res[:name]).to eq 'p_33470efd-1' }
it { expect(res[:if_type].to_s).to eq 'patch' }
it { expect(res[:if_provider].to_s).to eq 'lnx' }
end
end
end

View File

@ -0,0 +1,69 @@
require 'spec_helper'
describe Puppet::Type.type(:l2_patch).provider(:ovs) do
# NOTE! for bridges ['br1', 'br2'] jack names will be ['p_39a440c1-0', 'p_39a440c1-1']
let(:resource_br1) {
Puppet::Type.type(:l2_bridge).new(
:provider => 'lnx',
:name => 'br1',
:bridge => 'br1',
)
}
let(:provider_br1) { resource_br1.provider }
#let(:instance_br1_ovs) { provider_br1.class.instances }
let(:resource_patch) {
Puppet::Type.type(:l2_patch).new(
:provider => 'lnx',
:name => 'patch__br1--br2',
:bridges => ['br1', 'br2'],
:jacks => ['p_39a440c1-0', 'p_39a440c1-1'],
:mtu => '9000'
)
}
let(:provider_patch) { resource_patch.provider }
#let(:instance_patch_ovs) { provider_patch.class.instances }
describe "lnx-to-lnx patchcord" do
let(:resource_br2) {
Puppet::Type.type(:l2_bridge).new(
:provider => 'lnx',
:name => 'br2',
:bridge => 'br2',
)
}
let(:provider_br2) { resource_br2.provider }
#let(:instance_br2_ovs) { provider_br2.class.instances }
before(:each) do
puppet_debug_override()
provider_br1.class.stubs(:iproute)
provider_br2.class.stubs(:iproute)
provider_br1.class.stubs(:brctl).with(['addbr', 'br1']).returns(true)
provider_br2.class.stubs(:brctl).with(['addbr', 'br2']).returns(true)
provider_patch.class.stubs(:iproute).with([
'link', 'add', 'dev', 'p_39a440c1-0', 'type', 'veth', 'peer', 'name', 'p_39a440c1-1'
]).returns(true)
provider_patch.class.stubs(:get_bridge_list).returns({
'br1' => {:br_type => :lnx},
'br2' => {:br_type => :lnx},
})
provider_patch.class.stubs(:iproute).with(['link', 'set', 'dev', 'p_39a440c1-0', 'master', 'br1']).returns(true)
provider_patch.class.stubs(:iproute).with(['link', 'set', 'dev', 'p_39a440c1-1', 'master', 'br2']).returns(true)
provider_patch.class.stubs(:interface_up).with('p_39a440c1-0', true).returns(true)
provider_patch.class.stubs(:interface_up).with('p_39a440c1-1', true).returns(true)
end
it "Just create two bridges and connect it by patchcord" do
provider_br1.create
provider_br2.create
provider_patch.create
end
end
end

View File

@ -83,15 +83,16 @@ describe Puppet::Type.type(:l2_patch).provider(:ovs) do
provider_br1.class.stubs(:vsctl).with('add-br', 'br1').returns(true) provider_br1.class.stubs(:vsctl).with('add-br', 'br1').returns(true)
provider_br2.class.stubs(:iproute).with().returns(true) provider_br2.class.stubs(:iproute).with().returns(true)
provider_br2.class.stubs(:iproute).with('link', 'set', 'up', 'dev', 'br2').returns(true) provider_br2.class.stubs(:iproute).with('link', 'set', 'up', 'dev', 'br2').returns(true)
provider_br2.class.stubs(:brctl).with('addbr', 'br2').returns(true) provider_br2.stubs(:brctl).with(['addbr', 'br2']).returns(true)
provider_patch.class.stubs(:brctl).with('addif', 'br2', 'p_39a440c1-0').returns(true) provider_patch.class.stubs(:get_bridges_order_for_patch).with(['br1','br2']).returns(['br1','br2'])
File.stubs(:directory?).with('/sys/class/net/br2/bridge').returns(true)
provider_patch.class.stubs(:vsctl).with( provider_patch.class.stubs(:vsctl).with(
'--may-exist', 'add-port', 'br1', 'p_39a440c1-0', '--', 'set', 'Interface', 'p_39a440c1-0', 'type=internal' '--may-exist', 'add-port', 'br1', 'p_39a440c1-0', '--', 'set', 'Interface', 'p_39a440c1-0', 'type=internal'
).returns(true) ).returns(true)
File.stubs(:directory?).with('/sys/class/net/br2/bridge').returns(true)
provider_patch.class.stubs(:get_lnx_port_bridges_pairs).with().returns({}) provider_patch.class.stubs(:get_lnx_port_bridges_pairs).with().returns({})
provider_patch.class.stubs(:get_bridges_order_for_patch).with(['br1','br2']).returns(['br1','br2']) provider_patch.stubs(:brctl).with(['addif', 'br2', 'p_39a440c1-0']).returns(true)
provider_patch.class.stubs(:iproute).with('link', 'set', 'up', 'dev', 'p_39a440c1-0').returns(true) provider_patch.class.stubs(:iproute).with('link', 'set', 'up', 'dev', 'p_39a440c1-0').returns(true)
end end
it "Just create two bridges and connect it by patchcord" do it "Just create two bridges and connect it by patchcord" do
@ -100,6 +101,15 @@ describe Puppet::Type.type(:l2_patch).provider(:ovs) do
provider_patch.create provider_patch.create
end end
it "Patch was connected to another bridge" do
provider_br1.create
provider_br2.create
provider_patch.class.stubs(:get_lnx_port_bridges_pairs).with().returns({'p_39a440c1-0'=>{:bridge=>'br-lnx1', :br_type=>:lnx},})
provider_patch.stubs(:brctl).with(['delif', 'br-lnx1', 'p_39a440c1-0']).returns(true)
provider_patch.stubs(:brctl).with(['addif', 'br2', 'p_39a440c1-0']).returns(true)
provider_patch.create
end
end end
end end