Fix restoring lnx2lnx patch after reboot on CentOS7/RHEL7

Change-Id: I148edd31b83e761184a3135570c9b20b8527896c
Closes-bug: #1522481
This commit is contained in:
Stanislav Makar 2015-12-03 16:19:50 +00:00
parent 134d640af1
commit 6da29b4686
11 changed files with 267 additions and 8 deletions

View File

@ -0,0 +1,5 @@
#!/bin/sh
SCRIPT="/etc/sysconfig/network-scripts/pre-up-$1"
if [[ -x $SCRIPT ]] ; then
. $SCRIPT
fi

View File

@ -48,6 +48,7 @@ class Puppet::Provider::L23_stored_config_centos < Puppet::Provider::L23_stored_
:bond_downdelay => 'downdelay',
:ethtool => 'ETHTOOL_OPTS',
:routes => 'ROUTES',
:jacks => 'JACKS',
}
end
def property_mappings
@ -129,6 +130,12 @@ class Puppet::Provider::L23_stored_config_centos < Puppet::Provider::L23_stored_
hash.delete('PREFIX')
end
# reading preup file for patch if it exists
if preup_content = self.read_file("#{self.script_directory}/pre-up-ifcfg-#{dirty_iface_name}") and !preup_content.empty?
hash['JACKS'] = preup_content
hash['TYPE'] = 'Patch'
end
hash.delete('DEVICETYPE') if hash['DEVICETYPE']
# Do extra actions if ovs2lnx patch cord
@ -261,6 +268,18 @@ class Puppet::Provider::L23_stored_config_centos < Puppet::Provider::L23_stored_
return rv
end
def self.mangle__jacks(data)
#data should be
#ip link add p_3911f6cc-0 type veth peer name p_3911f6cc-1\nip link set up dev p_3911f6cc-1
rv = []
p "parse jacks #{data}"
data.split("\n").each do | line |
jacks = line.scan(/ip\s+link\s+add\s+([\w\-]+)\s+type\s+veth\s+peer\s+name\s+([\w\-]+)/).flatten
rv = jacks if !jacks.empty?
end
return rv
end
###
# Hash to file
def self.format_file(filename, providers)
@ -316,6 +335,14 @@ class Puppet::Provider::L23_stored_config_centos < Puppet::Provider::L23_stored_
self.remove_line_from_file('/etc/sysconfig/network', /GATEWAY.*/)
end
#writing the pre-up file for patch
if pairs['TYPE'].to_s == 'Patch' and pairs['JACKS']
patch_pre_up_filename = "#{self.script_directory}/pre-up-ifcfg-#{provider.name}"
self.write_file(patch_pre_up_filename, pairs['JACKS'])
pairs.delete('TYPE')
pairs.delete('JACKS')
end
pairs.each_pair do |key, val|
content << "#{key}=#{val}" if ! val.nil?
end
@ -326,12 +353,19 @@ class Puppet::Provider::L23_stored_config_centos < Puppet::Provider::L23_stored_
end
def self.read_file(file)
File.read file
content = ''
content = File.read(file) if File.exist?(file)
return content
end
def self.write_file(file, content)
File.open(file, 'w') do |fp|
fp.write content
debug("write_file(): writing the file #{file} \nwith content:\n#{content}")
begin
File.open(file, 'w') do |writing_file|
writing_file.write content.to_s
end
rescue
raise Puppet::Error, "write_file(): file #{file} can not be written!"
end
end
@ -425,5 +459,13 @@ class Puppet::Provider::L23_stored_config_centos < Puppet::Provider::L23_stored_
return rv
end
def self.unmangle__jacks(provider, data)
rv = []
rv << "ip link add #{data[0]} type veth peer name #{data[1]}"
rv << "ip link set up dev #{data[1]}"
rv.join("\n")
end
end
# vim: set ts=2 sw=2 et :

View File

@ -29,7 +29,7 @@ Puppet::Type.type(:l2_patch).provide(:lnx, :parent => Puppet::Provider::Lnx_base
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
_bridges = [jack[:bridge], peer[:bridge]]
_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]}"
@ -70,7 +70,7 @@ Puppet::Type.type(:l2_patch).provide(:lnx, :parent => Puppet::Provider::Lnx_base
_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 ])
self.class.brctl(['addif', br_name, @resource[:jacks][i]])
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]])
@ -92,9 +92,7 @@ Puppet::Type.type(:l2_patch).provide(:lnx, :parent => Puppet::Provider::Lnx_base
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
@property_hash[:jacks].each { |iface| self.class.set_mtu(iface, @property_flush[:mtu]) } if @property_hash[:jacks]
end
#todo: /sv: make ability of change bridges for RAW patchcords
@property_hash = resource.to_hash

View File

@ -12,5 +12,11 @@ class l23network::l2::centos_upndown_scripts {
mode => '0755',
content => template('l23network/centos_ifdown-local.erb'),
} ->
file {'/sbin/ifup-pre-local':
ensure => present,
owner => 'root',
mode => '0755',
source => 'puppet:///modules/l23network/centos_ifup-pre-local',
} ->
anchor { 'l23network::l2::centos_upndown_scripts': }
}

View File

@ -0,0 +1,6 @@
BOOTPROTO=none
IPADDR=192.168.88.2
DEVICE=br1
ONBOOT=yes
TYPE=Bridge
PREFIX=24

View File

@ -0,0 +1,6 @@
BOOTPROTO=none
IPADDR=192.168.99.2
DEVICE=br2
ONBOOT=yes
TYPE=Bridge
PREFIX=24

View File

@ -0,0 +1,4 @@
BOOTPROTO=none
DEVICE=p_33470efd-0
ONBOOT=yes
BRIDGE=br1

View File

@ -0,0 +1,4 @@
BOOTPROTO=none
DEVICE=p_33470efd-1
ONBOOT=yes
BRIDGE=br2

View File

@ -0,0 +1,2 @@
ip link add p_33470efd-0 type veth peer name p_33470efd-1
ip link set up dev p_33470efd-1

View File

@ -0,0 +1,2 @@
ip link add p_33470efd-0 type veth peer name p_33470efd-1
ip link set up dev p_33470efd-1

View File

@ -0,0 +1,184 @@
require 'spec_helper'
resources_map = {
:'br1' => {
:name => "br1",
:onboot => "yes",
:method => "static",
:if_type => "bridge",
:ipaddr => "192.168.88.2/24",
:provider => "lnx_centos7",
},
:'br2' => {
:name => "br2",
:onboot => "yes",
:method => "static",
:if_type => "bridge",
:ipaddr => "192.168.99.2/24",
:provider => "lnx_centos7",
},
:'p_33470efd-0' => {
:name => 'p_33470efd-0',
:if_type => 'patch',
:bridge => ["br1"],
:jacks => ['p_33470efd-0', 'p_33470efd-1'],
:provider => "lnx_centos7",
},
:'p_33470efd-1' => {
:name => "p_33470efd-1",
:if_type => 'patch',
:bridge => ["br2"],
:jacks => ['p_33470efd-0', 'p_33470efd-1'],
:provider => "lnx_centos7",
},
}
describe Puppet::Type.type(:l23_stored_config).provider(:lnx_centos7) 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()
subject.class.stubs(:script_directory).returns(fixture_path)
file_handle = mock
file_handle.stubs(:write).returns true
File.stubs(:open).yields(file_handle).returns(true)
end
def fixture_path
File.join(PROJECT_ROOT, 'spec', 'fixtures', 'provider', 'l23_stored_config', 'lnx_centos7__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(/BOOTPROTO=none/) }
it { expect(cfg_file).to match(/IPADDR=192.168.88.2/) }
it { expect(cfg_file).to match(/DEVICE=br1/) }
it { expect(cfg_file).to match(/ONBOOT=yes/) }
it { expect(cfg_file).to match(/TYPE=Bridge/) }
it { expect(cfg_file).to match(/PREFIX=24/) }
it { expect(cfg_file.split(/\n/).reject{|x| x=~/^\s*$/}.length). to eq(6) }
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(/BOOTPROTO=none/) }
it { expect(cfg_file).to match(/IPADDR=192.168.99.2/) }
it { expect(cfg_file).to match(/DEVICE=br2/) }
it { expect(cfg_file).to match(/ONBOOT=yes/) }
it { expect(cfg_file).to match(/TYPE=Bridge/) }
it { expect(cfg_file).to match(/PREFIX=24/) }
it { expect(cfg_file.split(/\n/).reject{|x| x=~/^\s*$/}.length). to eq(6) }
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(/BOOTPROTO=none/) }
it { expect(cfg_file).to match(/DEVICE=p_33470efd-0/) }
it { expect(cfg_file).to match(/BRIDGE=br1/) }
it { expect(cfg_file).to match(/ONBOOT=yes/) }
it { expect(cfg_file.split(/\n/).reject{|x| x=~/^\s*$/}.length). to eq(4) }
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(/BOOTPROTO=none/) }
it { expect(cfg_file).to match(/DEVICE=p_33470efd-1/) }
it { expect(cfg_file).to match(/BRIDGE=br2/) }
it { expect(cfg_file).to match(/ONBOOT=yes/) }
it { expect(cfg_file.split(/\n/).reject{|x| x=~/^\s*$/}.length). to eq(4) }
end
context 'file writing error for lnx2lnx patchcord p_33470efd-1' do
subject { providers[:'p_33470efd-1'] }
it do
file_handle = mock
file_handle.stubs(:write).raises(IOError)
File.stubs(:open).yields(file_handle).returns(true)
expect{ subject.class.format_file('filepath', [subject]) }.to raise_error(Puppet::Error, %r{.*file\s+.*-ifcfg-p_33470efd-1\s+can\s+not\s+be\s+written!})
end
end
end
context "when parsing config files" do
context 'for LNX bridge br1' do
let(:res) { subject.class.parse_file('ifcfg-br1', fixture_data('ifcfg-br1'))[0] }
it { expect(res[:method]).to eq 'manual' }
it { expect(res[:onboot]).to eq true }
it { expect(res[:name]).to eq 'br1' }
it { expect(res[:if_type].to_s).to eq 'bridge' }
it { expect(res[:provider].to_s).to eq 'lnx_centos7' }
end
context 'for LNX bridge br2' do
let(:res) { subject.class.parse_file('ifcfg-br2', fixture_data('ifcfg-br2'))[0] }
it { expect(res[:method]).to eq 'manual' }
it { expect(res[:onboot]).to eq true }
it { expect(res[:name]).to eq 'br2' }
it { expect(res[:if_type].to_s).to eq 'bridge' }
it { expect(res[:provider].to_s).to eq 'lnx_centos7' }
end
context 'for lnx2lnx patchcord p_33470efd-0' do
let(:res) { subject.class.parse_file('ifcfg-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[:provider].to_s).to eq 'lnx_centos7' }
end
context 'for lnx2lnx patchcord p_33470efd-1' do
let(:res) { subject.class.parse_file('ifcfg-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[:provider].to_s).to eq 'lnx_centos7' }
end
end
end