Refacfored a more suitable ovs_redhat provider
- Added a helper class/library to handle ifcfg content - Removed keep_ip and sleep parameters, replaced by automatic behaviour - No need for a redhat vs_bridge provider - Only port/bridge associated with a phyical interface get a ifcfg file managed - Requires Puppet 2.7.8+ Not using optional_commands anymore When the bridge is associated with an active physical interface - It will be initially populated from the existing interface file, inheriting its parameters Change-Id: I584fb1442de9a760b3a092f96cbfcbcd6776fdba
This commit is contained in:
parent
b7a15fc68c
commit
17b62e56e0
@ -1,51 +0,0 @@
|
||||
require "puppet"
|
||||
|
||||
Base="/etc/sysconfig/network-scripts/ifcfg-"
|
||||
|
||||
Puppet::Type.type(:vs_bridge).provide(:ovs_redhat) do
|
||||
desc "Openvswitch bridge manipulation for RedHat family OSs"
|
||||
|
||||
confine :osfamily => :redhat
|
||||
defaultfor :osfamily => :redhat
|
||||
|
||||
optional_commands :vsctl => "/usr/bin/ovs-vsctl",
|
||||
:ip => "/sbin/ip"
|
||||
|
||||
def exists?
|
||||
vsctl("br-exists", @resource[:name])
|
||||
rescue Puppet::ExecutionFailure
|
||||
return false
|
||||
end
|
||||
|
||||
def create
|
||||
vsctl("add-br", @resource[:name])
|
||||
ip("link", "set", @resource[:name], "up")
|
||||
external_ids = @resource[:external_ids] if @resource[:external_ids]
|
||||
end
|
||||
|
||||
def destroy
|
||||
vsctl("del-br", @resource[:name])
|
||||
end
|
||||
|
||||
def external_ids
|
||||
result = vsctl("br-get-external-id", @resource[:name])
|
||||
return result.split("\n").join(",")
|
||||
end
|
||||
|
||||
def external_ids=(value)
|
||||
old_ids = _split(external_ids)
|
||||
new_ids = _split(value)
|
||||
|
||||
new_ids.each_pair do |k,v|
|
||||
unless old_ids.has_key?(k)
|
||||
vsctl("br-set-external-id", @resource[:name], k, v)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def _split(string, splitter=",")
|
||||
return Hash[string.split(splitter).map{|i| i.split("=")}]
|
||||
end
|
||||
end
|
@ -1,105 +1,120 @@
|
||||
require "puppet"
|
||||
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'puppetx', 'redhat', 'ifcfg.rb'))
|
||||
|
||||
Puppet::Type.type(:vs_port).provide(:ovs_redhat) do
|
||||
desc "Openvswitch port manipulation for RedHat family OSs"
|
||||
BASE = '/etc/sysconfig/network-scripts/ifcfg-'
|
||||
|
||||
confine :osfamily => :redhat
|
||||
# When not seedling from interface file
|
||||
DEFAULT = {
|
||||
'ONBOOT' => 'yes',
|
||||
'BOOTPROTO' => 'dhcp',
|
||||
'PEERDNS' => 'no',
|
||||
'NM_CONTROLLED' => 'no',
|
||||
'NOZEROCONF' => 'yes' }
|
||||
|
||||
Puppet::Type.type(:vs_port).provide(:ovs_redhat, :parent => :ovs) do
|
||||
desc 'Openvswitch port manipulation for RedHat OSes family'
|
||||
|
||||
confine :osfamily => :redhat
|
||||
defaultfor :osfamily => :redhat
|
||||
|
||||
optional_commands :vsctl => "/usr/bin/ovs-vsctl",
|
||||
:sleep => "/bin/sleep"
|
||||
|
||||
def exists?
|
||||
vsctl("list-ports", @resource[:bridge]).include? @resource[:interface]
|
||||
end
|
||||
commands :ip => 'ip'
|
||||
commands :ifdown => 'ifdown'
|
||||
commands :ifup => 'ifup'
|
||||
commands :vsctl => 'ovs-vsctl'
|
||||
|
||||
def create
|
||||
if @resource[:keep_ip]
|
||||
create_bridge_file
|
||||
create_physical_interface_file
|
||||
activate_port
|
||||
unless vsctl('list-ports',
|
||||
@resource[:bridge]).include? @resource[:interface]
|
||||
super
|
||||
end
|
||||
|
||||
if interface_physical?
|
||||
template = DEFAULT
|
||||
extras = nil
|
||||
|
||||
if link?
|
||||
extras = dynamic_default if dynamic?
|
||||
if File.exist?(BASE + @resource[:interface])
|
||||
template = from_str(File.read(BASE + @resource[:interface]))
|
||||
end
|
||||
end
|
||||
|
||||
port = IFCFG::Port.new(@resource[:interface], @resource[:bridge])
|
||||
port.save(BASE + @resource[:interface])
|
||||
|
||||
bridge = IFCFG::Bridge.new(@resource[:bridge], template)
|
||||
bridge.set(extras) if extras
|
||||
bridge.save(BASE + @resource[:bridge])
|
||||
|
||||
ifdown(@resource[:bridge])
|
||||
ifdown(@resource[:interface])
|
||||
ifup(@resource[:interface])
|
||||
ifup(@resource[:bridge])
|
||||
end
|
||||
end
|
||||
|
||||
def exists?
|
||||
if interface_physical?
|
||||
super &&
|
||||
IFCFG::OVS.exists?(@resource[:interface]) &&
|
||||
IFCFG::OVS.exists?(@resource[:bridge])
|
||||
else
|
||||
vsctl("add-port", @resource[:bridge], @resource[:interface])
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
vsctl("del-port", @resource[:bridge], @resource[:interface])
|
||||
if interface_physical?
|
||||
ifdown(@resource[:bridge])
|
||||
ifdown(@resource[:interface])
|
||||
IFCFG::OVS.remove(@resource[:interface])
|
||||
IFCFG::OVS.remove(@resource[:bridge])
|
||||
end
|
||||
super
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def activate_port
|
||||
atomic_operation="ifdown #{@resource[:interface]};
|
||||
ovs-vsctl add-port #{@resource[:bridge]} #{@resource[:interface]};
|
||||
ifup #{@resource[:interface]};
|
||||
ifup #{@resource[:bridge]}"
|
||||
system(atomic_operation)
|
||||
sleep(@resource[:sleep]) if @resource[:sleep]
|
||||
end
|
||||
|
||||
def create_physical_interface_file
|
||||
file = File.open(Base + @resource[:interface], 'w+')
|
||||
file << "DEVICE=#{@resource[:interface]}\n"
|
||||
file << "DEVICETYPE=ovs\n"
|
||||
file << "TYPE=OVSPort\n"
|
||||
file << "BOOTPROTO=none\n"
|
||||
file << "OVS_BRIDGE=#{@resource[:bridge]}\n"
|
||||
file << "ONBOOT=yes\n"
|
||||
file.close
|
||||
def dynamic?
|
||||
device = ''
|
||||
device = ip('addr', 'show', @resource[:interface])
|
||||
return device =~ /dynamic/ ? true : false
|
||||
end
|
||||
|
||||
def search(file_name, value)
|
||||
File.open(file_name) { |file|
|
||||
file.each_line { |line|
|
||||
match = value.match(line)
|
||||
return match[0] if match
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def create_bridge_file
|
||||
bridge_file = File.open(Base + @resource[:bridge], 'w+')
|
||||
interface_file_name = Base + @resource[:interface]
|
||||
|
||||
# Ultimately this to go to vs_bridge
|
||||
bridge_file << "DEVICE=#{@resource[:bridge]}\n"
|
||||
bridge_file << "TYPE=OVSBridge\n"
|
||||
bridge_file << "DEVICETYPE=ovs\n"
|
||||
bridge_file << "ONBOOT=yes\n"
|
||||
# End ultimately
|
||||
|
||||
case search(interface_file_name, /bootproto=.*/i)
|
||||
when /dhcp/
|
||||
bridge_file << "OVSBOOTPROTO=dhcp\n"
|
||||
bridge_file << "OVSDHCPINTERFACES=#{@resource[:interface]}\n"
|
||||
when /static/, /none/
|
||||
bridge_file << "OVSBOOTPROTO=static\n"
|
||||
|
||||
ipaddr = search(interface_file_name, /ipaddr=.*/i)
|
||||
if ipaddr.class == String
|
||||
bridge_file << ipaddr + "\n"
|
||||
else
|
||||
raise RuntimeError, 'Undefined IP address'
|
||||
end
|
||||
|
||||
mask = search(interface_file_name, /(prefix|netmask)=.*/i)
|
||||
if mask.class == String
|
||||
bridge_file << mask + "\n"
|
||||
else
|
||||
raise RuntimeError, 'Undefined netmask or prefix'
|
||||
end
|
||||
else
|
||||
raise RuntimeError, 'Undefined boot protocol'
|
||||
def link?
|
||||
if File.read("/sys/class/net/#{@resource[:interface]}/operstate") =~ /up/
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
|
||||
# The idea here to have a fixed MAC address
|
||||
datapath_id = vsctl("get", "bridge", @resource[:bridge], 'datapath_id')
|
||||
bridge_mac_address = datapath_id[-14..-3].scan(/.{1,2}/).join(':') if datapath_id
|
||||
|
||||
if bridge_mac_address
|
||||
bridge_file << "OVS_EXTRA=\"set bridge #{@resource[:bridge]} other-config:hwaddr=#{bridge_mac_address}\"\n"
|
||||
end
|
||||
bridge_file.close
|
||||
rescue Errno::ENOENT
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
def dynamic_default
|
||||
list = { 'OVSDHCPINTERFACES' => @resource[:interface] }
|
||||
# Persistent MAC address taken from interface
|
||||
bridge_mac_address = File.read("/sys/class/net/#{@resource[:interface]}/address").chomp
|
||||
if bridge_mac_address != ''
|
||||
list.merge!({ 'OVS_EXTRA' =>
|
||||
"\"set bridge #{@resource[:bridge]} other-config:hwaddr=#{bridge_mac_address}\"" })
|
||||
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[:interface].sub(/:\d/, '')
|
||||
! Dir["/sys/class/net/#{interface}"].empty?
|
||||
end
|
||||
|
||||
def from_str(data)
|
||||
items = {}
|
||||
data.each_line do |line|
|
||||
if m = line.match(/^(.*)=(.*)$/)
|
||||
items.merge!(m[1] => m[2])
|
||||
end
|
||||
end
|
||||
items
|
||||
end
|
||||
end
|
||||
|
17
lib/puppet/provider/vs_port/ovs_redhat_el6.rb
Normal file
17
lib/puppet/provider/vs_port/ovs_redhat_el6.rb
Normal file
@ -0,0 +1,17 @@
|
||||
Puppet::Type.type(:vs_port).provide(:ovs_redhat_el6, :parent => :ovs_redhat) do
|
||||
desc 'Openvswitch port manipulation for RedHat OSes family'
|
||||
|
||||
confine :osfamily => :redhat, :operatingsystemmajrelease => 6
|
||||
defaultfor :osfamily => :redhat, :operatingsystemmajrelease => 6
|
||||
|
||||
private
|
||||
|
||||
def dynamic?
|
||||
# iproute doesn't behave as expected on rhel6 for dynamic interfaces
|
||||
if File.read(BASE + @resource[:interface]) =~ /^BOOTPROTO=['"]?dhcp['"]?$/
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
@ -16,7 +16,7 @@ Puppet::Type.newtype(:vs_port) do
|
||||
end
|
||||
|
||||
newparam(:bridge) do
|
||||
desc "What bridge to use"
|
||||
desc 'The bridge to attach to'
|
||||
|
||||
validate do |value|
|
||||
if !value.is_a?(String)
|
||||
@ -25,24 +25,6 @@ Puppet::Type.newtype(:vs_port) do
|
||||
end
|
||||
end
|
||||
|
||||
newparam(:keep_ip) do
|
||||
desc "True: keep physical interface's details and assign them to the bridge"
|
||||
|
||||
defaultto false
|
||||
end
|
||||
|
||||
newparam(:sleep) do
|
||||
desc "Waiting time, in seconds (0 by default), for network to sync after activating port, used with keep_ip only"
|
||||
|
||||
defaultto '0'
|
||||
|
||||
validate do |value|
|
||||
if value.to_i.class != Fixnum || value.to_i < 0
|
||||
raise ArgumentError, "sleep requires a positive integer"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
autorequire(:vs_bridge) do
|
||||
self[:bridge] if self[:bridge]
|
||||
end
|
||||
|
82
lib/puppetx/redhat/ifcfg.rb
Normal file
82
lib/puppetx/redhat/ifcfg.rb
Normal file
@ -0,0 +1,82 @@
|
||||
module IFCFG
|
||||
class OVS
|
||||
attr_reader :ifcfg
|
||||
|
||||
def self.exists?(name)
|
||||
File.exist?(BASE + name)
|
||||
end
|
||||
|
||||
def self.remove(name)
|
||||
File.delete(BASE + name)
|
||||
rescue Errno::ENOENT
|
||||
end
|
||||
|
||||
def initialize(name, seed=nil)
|
||||
@name = name
|
||||
@ifcfg = {}
|
||||
set(seed)
|
||||
set_key('DEVICE', @name)
|
||||
set_key('DEVICETYPE', 'ovs')
|
||||
replace_key('BOOTPROTO', 'OVSBOOTPROTO') if self.class == IFCFG::Bridge
|
||||
end
|
||||
|
||||
def del_key(key)
|
||||
@ifcfg.delete(key)
|
||||
end
|
||||
|
||||
def key?(key)
|
||||
@ifcfg.has_key?(key)
|
||||
end
|
||||
|
||||
def key(key)
|
||||
@ifcfg.has_key?(key)
|
||||
end
|
||||
|
||||
def replace_key(key, new_key)
|
||||
value = @ifcfg[key]
|
||||
@ifcfg.delete(key)
|
||||
set_key(new_key, value)
|
||||
end
|
||||
|
||||
def set(list)
|
||||
if list != nil && list.class == Hash
|
||||
list.each { |key, value| set_key(key, value) }
|
||||
end
|
||||
end
|
||||
|
||||
def set_key(key, value)
|
||||
@ifcfg.delete_if { |k, v| k == key } if self.key?(key)
|
||||
@ifcfg.merge!({key => value })
|
||||
end
|
||||
|
||||
def to_s
|
||||
str = ''
|
||||
@ifcfg.each { |x, y|
|
||||
str << "#{x}=#{y}\n"
|
||||
}
|
||||
str
|
||||
end
|
||||
|
||||
def save(filename)
|
||||
File.open(filename, 'w') { |file| file << self.to_s }
|
||||
end
|
||||
end
|
||||
|
||||
class Bridge < OVS
|
||||
def initialize(name, template=nil)
|
||||
super(name, template)
|
||||
set_key('TYPE', 'OVSBridge')
|
||||
del_key('HWADDR')
|
||||
end
|
||||
end
|
||||
|
||||
class Port < OVS
|
||||
def initialize(name, bridge)
|
||||
super(name)
|
||||
set_key('TYPE', 'OVSPort')
|
||||
set_key('OVS_BRIDGE', bridge)
|
||||
set_key('ONBOOT', 'yes')
|
||||
set_key('BOOTPROTO', 'none')
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue
Block a user