178 lines
4.3 KiB
Ruby
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
|