puppet-vswitch/lib/puppet/provider/vs_port/ovs_redhat.rb

178 lines
4.3 KiB
Ruby

require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'puppetx', 'redhat', 'ifcfg.rb'))
require File.expand_path(File.join(File.dirname(__FILE__), '.','ovs.rb'))
Puppet::Type.type(:vs_port).provide(
:ovs_redhat,
:parent => Puppet::Type.type(:vs_port).provider(:ovs)
) do
desc 'Openvswitch port manipulation for RedHat OSes family'
BASE ||= '/etc/sysconfig/network-scripts/ifcfg-'
# When not seedling from interface file
DEFAULT ||= {
'ONBOOT' => 'yes',
'BOOTPROTO' => 'dhcp',
'PEERDNS' => 'no',
'NM_CONTROLLED' => 'no',
'NOZEROCONF' => 'yes'
}
confine :osfamily => :redhat
defaultfor :osfamily => :redhat
commands :ip => 'ip'
commands :ifdown => 'ifdown'
commands :ifup => 'ifup'
commands :vsctl => 'ovs-vsctl'
def initialize(value={})
super(value)
# Set interface property although it's not really
# supported on this provider. This ensures that all
# methodes inherited from the ovs provider work as
# expected.
@resource[:interface] = @resource[:port]
end
def create
unless vsctl('list-ports',
@resource[:bridge]).include? @resource[:port]
super
end
if interface_physical?
template = DEFAULT
extras = { 'OVS_EXTRA' => "\"set bridge #{@resource[:bridge]} fail_mode=#{@resource[:fail_mode]}\"" }
if link?
extras = dynamic_default if dynamic?
if File.exist?(BASE + @resource[:port])
template = cleared(from_str(File.read(BASE + @resource[:port])))
end
end
port = IFCFG::Port.new(@resource[:port], @resource[:bridge])
if vlan?
port.set('VLAN' => 'yes')
end
if bonding?
port.set('BONDING_MASTER' => 'yes')
config = from_str(File.read(BASE + @resource[:port]))
port.set('BONDING_OPTS' => config['BONDING_OPTS']) if config.has_key?('BONDING_OPTS')
end
port.save(BASE + @resource[:port])
bridge = IFCFG::Bridge.new(@resource[:bridge], template)
bridge.set(extras) if extras
bridge.save(BASE + @resource[:bridge])
ifdown(@resource[:bridge])
ifdown(@resource[:port])
ifup(@resource[:port])
ifup(@resource[:bridge])
end
end
def exists?
if interface_physical?
super &&
IFCFG::OVS.exists?(@resource[:port]) &&
IFCFG::OVS.exists?(@resource[:bridge])
else
super
end
end
def destroy
if interface_physical?
ifdown(@resource[:bridge])
ifdown(@resource[:port])
IFCFG::OVS.remove(@resource[:port])
IFCFG::OVS.remove(@resource[:bridge])
end
super
end
private
def bonding?
# To do: replace with iproute2 commands
if File.exists?("/proc/net/bonding/#{@resource[:port]}")
return true
else
return false
end
rescue Errno::ENOENT
return false
end
def dynamic?
device = ''
device = ip('addr', 'show', @resource[:port])
return device =~ /dynamic/ ? true : false
end
def link?
if File.read("/sys/class/net/#{@resource[:port]}/operstate") =~ /up/
return true
else
return false
end
rescue Errno::ENOENT
return false
end
def dynamic_default
list = { 'OVSDHCPINTERFACES' => @resource[:port] }
# Persistent MAC address taken from interface
bridge_mac_address = File.read("/sys/class/net/#{@resource[:port]}/address").chomp
if bridge_mac_address != ''
list.merge!({ 'OVS_EXTRA' =>
"\"set bridge #{@resource[:bridge]} other-config:hwaddr=#{bridge_mac_address} fail_mode=#{@resource[:fail_mode]}\"" })
end
list
end
def interface_physical?
# OVS ports don't have entries in /sys/class/net
# Alias interfaces (ethX:Y) must use ethX entries
interface = @resource[:port].sub(/:\d/, '')
! Dir["/sys/class/net/#{interface}"].empty?
end
def from_str(data)
items = {}
data.each_line do |line|
if m = line.match(/^([A-Za-z_]*)=(.*)$/)
items.merge!(m[1] => m[2])
end
end
items
end
def cleared(data)
data.each do |key, value|
case key
when /vlan/i
data.delete(key)
when /bonding/i
data.delete(key)
end
end
end
def vlan?
if File.read('/proc/net/vlan/config') =~ /#{@resource[:port]}/
return true
else
return false
end
rescue Errno::ENOENT
return false
end
end