Added puppetlabs-firewall (required by puppetlabs-postgresql), updated the other modules.
This commit is contained in:
parent
5f4b7a3b72
commit
dee66abcdd
137 changed files with 11118 additions and 419 deletions
|
@ -0,0 +1,32 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe 'firewall::linux::archlinux', :type => :class do
|
||||
it { should contain_service('iptables').with(
|
||||
:ensure => 'running',
|
||||
:enable => 'true'
|
||||
)}
|
||||
it { should contain_service('ip6tables').with(
|
||||
:ensure => 'running',
|
||||
:enable => 'true'
|
||||
)}
|
||||
|
||||
context 'ensure => stopped' do
|
||||
let(:params) {{ :ensure => 'stopped' }}
|
||||
it { should contain_service('iptables').with(
|
||||
:ensure => 'stopped'
|
||||
)}
|
||||
it { should contain_service('ip6tables').with(
|
||||
:ensure => 'stopped'
|
||||
)}
|
||||
end
|
||||
|
||||
context 'enable => false' do
|
||||
let(:params) {{ :enable => 'false' }}
|
||||
it { should contain_service('iptables').with(
|
||||
:enable => 'false'
|
||||
)}
|
||||
it { should contain_service('ip6tables').with(
|
||||
:enable => 'false'
|
||||
)}
|
||||
end
|
||||
end
|
|
@ -0,0 +1,19 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe 'firewall::linux::debian', :type => :class do
|
||||
it { should contain_package('iptables-persistent').with(
|
||||
:ensure => 'present'
|
||||
)}
|
||||
it { should contain_service('iptables-persistent').with(
|
||||
:ensure => nil,
|
||||
:enable => 'true',
|
||||
:require => 'Package[iptables-persistent]'
|
||||
)}
|
||||
|
||||
context 'enable => false' do
|
||||
let(:params) {{ :enable => 'false' }}
|
||||
it { should contain_service('iptables-persistent').with(
|
||||
:enable => 'false'
|
||||
)}
|
||||
end
|
||||
end
|
|
@ -0,0 +1,22 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe 'firewall::linux::redhat', :type => :class do
|
||||
it { should contain_service('iptables').with(
|
||||
:ensure => 'running',
|
||||
:enable => 'true'
|
||||
)}
|
||||
|
||||
context 'ensure => stopped' do
|
||||
let(:params) {{ :ensure => 'stopped' }}
|
||||
it { should contain_service('iptables').with(
|
||||
:ensure => 'stopped'
|
||||
)}
|
||||
end
|
||||
|
||||
context 'enable => false' do
|
||||
let(:params) {{ :enable => 'false' }}
|
||||
it { should contain_service('iptables').with(
|
||||
:enable => 'false'
|
||||
)}
|
||||
end
|
||||
end
|
30
modules/firewall/spec/unit/classes/firewall_linux_spec.rb
Normal file
30
modules/firewall/spec/unit/classes/firewall_linux_spec.rb
Normal file
|
@ -0,0 +1,30 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe 'firewall::linux', :type => :class do
|
||||
let(:facts_default) {{ :kernel => 'Linux' }}
|
||||
it { should contain_package('iptables').with_ensure('present') }
|
||||
|
||||
context 'RedHat like' do
|
||||
%w{RedHat CentOS Fedora}.each do |os|
|
||||
context "operatingsystem => #{os}" do
|
||||
releases = (os == 'Fedora' ? [14,15,'Rawhide'] : [6,7])
|
||||
releases.each do |osrel|
|
||||
context "operatingsystemrelease => #{osrel}" do
|
||||
let(:facts) { facts_default.merge({ :operatingsystem => os,
|
||||
:operatingsystemrelease => osrel}) }
|
||||
it { should contain_class('firewall::linux::redhat').with_require('Package[iptables]') }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'Debian like' do
|
||||
%w{Debian Ubuntu}.each do |os|
|
||||
context "operatingsystem => #{os}" do
|
||||
let(:facts) { facts_default.merge({ :operatingsystem => os }) }
|
||||
it { should contain_class('firewall::linux::debian').with_require('Package[iptables]') }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
25
modules/firewall/spec/unit/classes/firewall_spec.rb
Normal file
25
modules/firewall/spec/unit/classes/firewall_spec.rb
Normal file
|
@ -0,0 +1,25 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe 'firewall', :type => :class do
|
||||
context 'kernel => Linux' do
|
||||
let(:facts) {{ :kernel => 'Linux' }}
|
||||
it { should contain_class('firewall::linux').with_ensure('running') }
|
||||
end
|
||||
|
||||
context 'kernel => Windows' do
|
||||
let(:facts) {{ :kernel => 'Windows' }}
|
||||
it { expect { should contain_class('firewall::linux') }.to raise_error(Puppet::Error) }
|
||||
end
|
||||
|
||||
context 'ensure => stopped' do
|
||||
let(:facts) {{ :kernel => 'Linux' }}
|
||||
let(:params) {{ :ensure => 'stopped' }}
|
||||
it { should contain_class('firewall::linux').with_ensure('stopped') }
|
||||
end
|
||||
|
||||
context 'ensure => test' do
|
||||
let(:facts) {{ :kernel => 'Linux' }}
|
||||
let(:params) {{ :ensure => 'test' }}
|
||||
it { expect { should contain_class('firewall::linux') }.to raise_error(Puppet::Error) }
|
||||
end
|
||||
end
|
|
@ -0,0 +1,35 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe "Facter::Util::Fact iptables_persistent_version" do
|
||||
before { Facter.clear }
|
||||
let(:dpkg_cmd) { "dpkg-query -Wf '${Version}' iptables-persistent 2>/dev/null" }
|
||||
|
||||
{
|
||||
"Debian" => "0.0.20090701",
|
||||
"Ubuntu" => "0.5.3ubuntu2",
|
||||
}.each do |os, ver|
|
||||
describe "#{os} package installed" do
|
||||
before {
|
||||
allow(Facter.fact(:operatingsystem)).to receive(:value).and_return(os)
|
||||
allow(Facter::Util::Resolution).to receive(:exec).with(dpkg_cmd).
|
||||
and_return(ver)
|
||||
}
|
||||
it { Facter.fact(:iptables_persistent_version).value.should == ver }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Ubuntu package not installed' do
|
||||
before {
|
||||
allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('Ubuntu')
|
||||
allow(Facter::Util::Resolution).to receive(:exec).with(dpkg_cmd).
|
||||
and_return(nil)
|
||||
}
|
||||
it { Facter.fact(:iptables_persistent_version).value.should be_nil }
|
||||
end
|
||||
|
||||
describe 'CentOS not supported' do
|
||||
before { allow(Facter.fact(:operatingsystem)).to receive(:value).
|
||||
and_return("CentOS") }
|
||||
it { Facter.fact(:iptables_persistent_version).value.should be_nil }
|
||||
end
|
||||
end
|
23
modules/firewall/spec/unit/facter/iptables_spec.rb
Normal file
23
modules/firewall/spec/unit/facter/iptables_spec.rb
Normal file
|
@ -0,0 +1,23 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe "Facter::Util::Fact" do
|
||||
before {
|
||||
Facter.clear
|
||||
allow(Facter.fact(:kernel)).to receive(:value).and_return('Linux')
|
||||
allow(Facter.fact(:kernelrelease)).to receive(:value).and_return('2.6')
|
||||
}
|
||||
|
||||
describe 'iptables_version' do
|
||||
it {
|
||||
allow(Facter::Util::Resolution).to receive(:exec).with('iptables --version').
|
||||
and_return('iptables v1.4.7')
|
||||
Facter.fact(:iptables_version).value.should == '1.4.7'
|
||||
}
|
||||
end
|
||||
|
||||
describe 'ip6tables_version' do
|
||||
before { allow(Facter::Util::Resolution).to receive(:exec).
|
||||
with('ip6tables --version').and_return('ip6tables v1.4.7') }
|
||||
it { Facter.fact(:ip6tables_version).value.should == '1.4.7' }
|
||||
end
|
||||
end
|
227
modules/firewall/spec/unit/puppet/provider/iptables_chain_spec.rb
Executable file
227
modules/firewall/spec/unit/puppet/provider/iptables_chain_spec.rb
Executable file
|
@ -0,0 +1,227 @@
|
|||
#!/usr/bin/env rspec
|
||||
|
||||
require 'spec_helper'
|
||||
if Puppet.version < '3.4.0'
|
||||
require 'puppet/provider/confine/exists'
|
||||
else
|
||||
require 'puppet/confine/exists'
|
||||
end
|
||||
|
||||
describe 'iptables chain provider detection' do
|
||||
if Puppet.version < '3.4.0'
|
||||
let(:exists) {
|
||||
Puppet::Provider::Confine::Exists
|
||||
}
|
||||
else
|
||||
let(:exists) {
|
||||
Puppet::Confine::Exists
|
||||
}
|
||||
end
|
||||
|
||||
before :each do
|
||||
# Reset the default provider
|
||||
Puppet::Type.type(:firewallchain).defaultprovider = nil
|
||||
end
|
||||
|
||||
it "should default to iptables provider if /sbin/(eb|ip|ip6)tables[-save] exists" do
|
||||
# Stub lookup for /sbin/iptables & /sbin/iptables-save
|
||||
allow(exists).to receive(:which).with("ebtables").
|
||||
and_return "/sbin/ebtables"
|
||||
allow(exists).to receive(:which).with("ebtables-save").
|
||||
and_return "/sbin/ebtables-save"
|
||||
|
||||
allow(exists).to receive(:which).with("iptables").
|
||||
and_return "/sbin/iptables"
|
||||
allow(exists).to receive(:which).with("iptables-save").
|
||||
and_return "/sbin/iptables-save"
|
||||
|
||||
allow(exists).to receive(:which).with("ip6tables").
|
||||
and_return "/sbin/ip6tables"
|
||||
allow(exists).to receive(:which).with("ip6tables-save").
|
||||
and_return "/sbin/ip6tables-save"
|
||||
|
||||
# Every other command should return false so we don't pick up any
|
||||
# other providers
|
||||
allow(exists).to receive(:which).with() { |value|
|
||||
value !~ /(eb|ip|ip6)tables(-save)?$/
|
||||
}.and_return false
|
||||
|
||||
# Create a resource instance and make sure the provider is iptables
|
||||
resource = Puppet::Type.type(:firewallchain).new({
|
||||
:name => 'test:filter:IPv4',
|
||||
})
|
||||
expect(resource.provider.class.to_s).to eq("Puppet::Type::Firewallchain::ProviderIptables_chain")
|
||||
end
|
||||
end
|
||||
|
||||
describe 'iptables chain provider' do
|
||||
let(:provider) { Puppet::Type.type(:firewallchain).provider(:iptables_chain) }
|
||||
let(:resource) {
|
||||
Puppet::Type.type(:firewallchain).new({
|
||||
:name => ':test:',
|
||||
})
|
||||
}
|
||||
|
||||
before :each do
|
||||
allow(Puppet::Type::Firewallchain).to receive(:defaultprovider).and_return provider
|
||||
allow(provider).to receive(:command).with(:ebtables_save).and_return "/sbin/ebtables-save"
|
||||
allow(provider).to receive(:command).with(:iptables_save).and_return "/sbin/iptables-save"
|
||||
allow(provider).to receive(:command).with(:ip6tables_save).and_return "/sbin/ip6tables-save"
|
||||
end
|
||||
|
||||
it 'should be able to get a list of existing rules' do
|
||||
# Pretend to return nil from iptables
|
||||
allow(provider).to receive(:execute).with(['/sbin/ip6tables-save']).and_return("")
|
||||
allow(provider).to receive(:execute).with(['/sbin/ebtables-save']).and_return("")
|
||||
allow(provider).to receive(:execute).with(['/sbin/iptables-save']).and_return("")
|
||||
|
||||
provider.instances.each do |chain|
|
||||
expect(chain).to be_instance_of(provider)
|
||||
expect(chain.properties[:provider].to_s).to eq(provider.name.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe 'iptables chain resource parsing' do
|
||||
let(:provider) { Puppet::Type.type(:firewallchain).provider(:iptables_chain) }
|
||||
|
||||
before :each do
|
||||
ebtables = ['BROUTE:BROUTING:ethernet',
|
||||
'BROUTE:broute:ethernet',
|
||||
':INPUT:ethernet',
|
||||
':FORWARD:ethernet',
|
||||
':OUTPUT:ethernet',
|
||||
':filter:ethernet',
|
||||
':filterdrop:ethernet',
|
||||
':filterreturn:ethernet',
|
||||
'NAT:PREROUTING:ethernet',
|
||||
'NAT:OUTPUT:ethernet',
|
||||
'NAT:POSTROUTING:ethernet',
|
||||
]
|
||||
allow(provider).to receive(:execute).with(['/sbin/ebtables-save']).and_return('
|
||||
*broute
|
||||
:BROUTING ACCEPT
|
||||
:broute ACCEPT
|
||||
|
||||
*filter
|
||||
:INPUT ACCEPT
|
||||
:FORWARD ACCEPT
|
||||
:OUTPUT ACCEPT
|
||||
:filter ACCEPT
|
||||
:filterdrop DROP
|
||||
:filterreturn RETURN
|
||||
|
||||
*nat
|
||||
:PREROUTING ACCEPT
|
||||
:OUTPUT ACCEPT
|
||||
:POSTROUTING ACCEPT
|
||||
')
|
||||
|
||||
iptables = [
|
||||
'raw:PREROUTING:IPv4',
|
||||
'raw:OUTPUT:IPv4',
|
||||
'raw:raw:IPv4',
|
||||
'mangle:PREROUTING:IPv4',
|
||||
'mangle:INPUT:IPv4',
|
||||
'mangle:FORWARD:IPv4',
|
||||
'mangle:OUTPUT:IPv4',
|
||||
'mangle:POSTROUTING:IPv4',
|
||||
'mangle:mangle:IPv4',
|
||||
'NAT:PREROUTING:IPv4',
|
||||
'NAT:OUTPUT:IPv4',
|
||||
'NAT:POSTROUTING:IPv4',
|
||||
'NAT:mangle:IPv4',
|
||||
'NAT:mangle:IPv4',
|
||||
'NAT:mangle:IPv4',
|
||||
':$5()*&%\'"^$): :IPv4',
|
||||
]
|
||||
allow(provider).to receive(:execute).with(['/sbin/iptables-save']).and_return('
|
||||
# Generated by iptables-save v1.4.9 on Mon Jan 2 01:20:06 2012
|
||||
*raw
|
||||
:PREROUTING ACCEPT [12:1780]
|
||||
:OUTPUT ACCEPT [19:1159]
|
||||
:raw - [0:0]
|
||||
COMMIT
|
||||
# Completed on Mon Jan 2 01:20:06 2012
|
||||
# Generated by iptables-save v1.4.9 on Mon Jan 2 01:20:06 2012
|
||||
*mangle
|
||||
:PREROUTING ACCEPT [12:1780]
|
||||
:INPUT ACCEPT [12:1780]
|
||||
:FORWARD ACCEPT [0:0]
|
||||
:OUTPUT ACCEPT [19:1159]
|
||||
:POSTROUTING ACCEPT [19:1159]
|
||||
:mangle - [0:0]
|
||||
COMMIT
|
||||
# Completed on Mon Jan 2 01:20:06 2012
|
||||
# Generated by iptables-save v1.4.9 on Mon Jan 2 01:20:06 2012
|
||||
*nat
|
||||
:PREROUTING ACCEPT [2242:639750]
|
||||
:OUTPUT ACCEPT [5176:326206]
|
||||
:POSTROUTING ACCEPT [5162:325382]
|
||||
COMMIT
|
||||
# Completed on Mon Jan 2 01:20:06 2012
|
||||
# Generated by iptables-save v1.4.9 on Mon Jan 2 01:20:06 2012
|
||||
*filter
|
||||
:INPUT ACCEPT [0:0]
|
||||
:FORWARD DROP [0:0]
|
||||
:OUTPUT ACCEPT [5673:420879]
|
||||
:$5()*&%\'"^$): - [0:0]
|
||||
COMMIT
|
||||
# Completed on Mon Jan 2 01:20:06 2012
|
||||
')
|
||||
ip6tables = [
|
||||
'raw:PREROUTING:IPv6',
|
||||
'raw:OUTPUT:IPv6',
|
||||
'raw:ff:IPv6',
|
||||
'mangle:PREROUTING:IPv6',
|
||||
'mangle:INPUT:IPv6',
|
||||
'mangle:FORWARD:IPv6',
|
||||
'mangle:OUTPUT:IPv6',
|
||||
'mangle:POSTROUTING:IPv6',
|
||||
'mangle:ff:IPv6',
|
||||
':INPUT:IPv6',
|
||||
':FORWARD:IPv6',
|
||||
':OUTPUT:IPv6',
|
||||
':test:IPv6',
|
||||
]
|
||||
allow(provider).to receive(:execute).with(['/sbin/ip6tables-save']).and_return('
|
||||
# Generated by ip6tables-save v1.4.9 on Mon Jan 2 01:31:39 2012
|
||||
*raw
|
||||
:PREROUTING ACCEPT [2173:489241]
|
||||
:OUTPUT ACCEPT [0:0]
|
||||
:ff - [0:0]
|
||||
COMMIT
|
||||
# Completed on Mon Jan 2 01:31:39 2012
|
||||
# Generated by ip6tables-save v1.4.9 on Mon Jan 2 01:31:39 2012
|
||||
*mangle
|
||||
:PREROUTING ACCEPT [2301:518373]
|
||||
:INPUT ACCEPT [0:0]
|
||||
:FORWARD ACCEPT [0:0]
|
||||
:OUTPUT ACCEPT [0:0]
|
||||
:POSTROUTING ACCEPT [0:0]
|
||||
:ff - [0:0]
|
||||
COMMIT
|
||||
# Completed on Mon Jan 2 01:31:39 2012
|
||||
# Generated by ip6tables-save v1.4.9 on Mon Jan 2 01:31:39 2012
|
||||
*filter
|
||||
:INPUT ACCEPT [0:0]
|
||||
:FORWARD DROP [0:0]
|
||||
:OUTPUT ACCEPT [20:1292]
|
||||
:test - [0:0]
|
||||
COMMIT
|
||||
# Completed on Mon Jan 2 01:31:39 2012
|
||||
')
|
||||
@all = ebtables + iptables + ip6tables
|
||||
# IPv4 and IPv6 names also exist as resources {table}:{chain}:IP and {table}:{chain}:
|
||||
iptables.each { |name| @all += [ name[0..-3], name[0..-5] ] }
|
||||
ip6tables.each { |name| @all += [ name[0..-3], name[0..-5] ] }
|
||||
end
|
||||
|
||||
it 'should have all in parsed resources' do
|
||||
provider.instances.each do |resource|
|
||||
@all.include?(resource.name)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
410
modules/firewall/spec/unit/puppet/provider/iptables_spec.rb
Normal file
410
modules/firewall/spec/unit/puppet/provider/iptables_spec.rb
Normal file
|
@ -0,0 +1,410 @@
|
|||
#!/usr/bin/env rspec
|
||||
|
||||
require 'spec_helper'
|
||||
if Puppet.version < '3.4.0'
|
||||
require 'puppet/provider/confine/exists'
|
||||
else
|
||||
require 'puppet/confine/exists'
|
||||
end
|
||||
|
||||
describe 'iptables provider detection' do
|
||||
if Puppet.version < '3.4.0'
|
||||
let(:exists) {
|
||||
Puppet::Provider::Confine::Exists
|
||||
}
|
||||
else
|
||||
let(:exists) {
|
||||
Puppet::Confine::Exists
|
||||
}
|
||||
end
|
||||
|
||||
before :each do
|
||||
# Reset the default provider
|
||||
Puppet::Type.type(:firewall).defaultprovider = nil
|
||||
end
|
||||
|
||||
it "should default to iptables provider if /sbin/iptables[-save] exists" do
|
||||
# Stub lookup for /sbin/iptables & /sbin/iptables-save
|
||||
allow(exists).to receive(:which).with("iptables").
|
||||
and_return "/sbin/iptables"
|
||||
allow(exists).to receive(:which).with("iptables-save").
|
||||
and_return "/sbin/iptables-save"
|
||||
|
||||
# Every other command should return false so we don't pick up any
|
||||
# other providers
|
||||
allow(exists).to receive(:which).with() { |value|
|
||||
! ["iptables","iptables-save"].include?(value)
|
||||
}.and_return false
|
||||
|
||||
# Create a resource instance and make sure the provider is iptables
|
||||
resource = Puppet::Type.type(:firewall).new({
|
||||
:name => '000 test foo',
|
||||
})
|
||||
expect(resource.provider.class.to_s).to eq("Puppet::Type::Firewall::ProviderIptables")
|
||||
end
|
||||
end
|
||||
|
||||
describe 'iptables provider' do
|
||||
let(:provider) { Puppet::Type.type(:firewall).provider(:iptables) }
|
||||
let(:resource) {
|
||||
Puppet::Type.type(:firewall).new({
|
||||
:name => '000 test foo',
|
||||
:action => 'accept',
|
||||
})
|
||||
}
|
||||
|
||||
before :each do
|
||||
allow(Puppet::Type::Firewall).to receive(:defaultprovider).and_return provider
|
||||
allow(provider).to receive(:command).with(:iptables_save).and_return "/sbin/iptables-save"
|
||||
|
||||
# Stub iptables version
|
||||
allow(Facter.fact(:iptables_version)).to receive(:value).and_return("1.4.2")
|
||||
|
||||
allow(Puppet::Util::Execution).to receive(:execute).and_return ""
|
||||
allow(Puppet::Util).to receive(:which).with("iptables-save").
|
||||
and_return "/sbin/iptables-save"
|
||||
end
|
||||
|
||||
it 'should be able to get a list of existing rules' do
|
||||
provider.instances.each do |rule|
|
||||
expect(rule).to be_instance_of(provider)
|
||||
expect(rule.properties[:provider].to_s).to eq(provider.name.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should ignore lines with fatal errors' do
|
||||
allow(Puppet::Util::Execution).to receive(:execute).with(['/sbin/iptables-save']).
|
||||
and_return("FATAL: Could not load /lib/modules/2.6.18-028stab095.1/modules.dep: No such file or directory")
|
||||
|
||||
expect(provider.instances.length).to be_zero
|
||||
end
|
||||
|
||||
describe '#insert_order' do
|
||||
let(:iptables_save_output) { [
|
||||
'-A INPUT -s 8.0.0.2/32 -p tcp -m multiport --ports 100 -m comment --comment "100 test" -j ACCEPT',
|
||||
'-A INPUT -s 8.0.0.3/32 -p tcp -m multiport --ports 200 -m comment --comment "200 test" -j ACCEPT',
|
||||
'-A INPUT -s 8.0.0.4/32 -p tcp -m multiport --ports 300 -m comment --comment "300 test" -j ACCEPT'
|
||||
] }
|
||||
let(:resources) do
|
||||
iptables_save_output.each_with_index.collect { |l,index| provider.rule_to_hash(l, 'filter', index) }
|
||||
end
|
||||
let(:providers) do
|
||||
resources.collect { |r| provider.new(r) }
|
||||
end
|
||||
it 'understands offsets for adding rules to the beginning' do
|
||||
resource = Puppet::Type.type(:firewall).new({ :name => '001 test', })
|
||||
allow(resource.provider.class).to receive(:instances).and_return(providers)
|
||||
expect(resource.provider.insert_order).to eq(1) # 1-indexed
|
||||
end
|
||||
it 'understands offsets for editing rules at the beginning' do
|
||||
resource = Puppet::Type.type(:firewall).new({ :name => '100 test', })
|
||||
allow(resource.provider.class).to receive(:instances).and_return(providers)
|
||||
expect(resource.provider.insert_order).to eq(1)
|
||||
end
|
||||
it 'understands offsets for adding rules to the middle' do
|
||||
resource = Puppet::Type.type(:firewall).new({ :name => '101 test', })
|
||||
allow(resource.provider.class).to receive(:instances).and_return(providers)
|
||||
expect(resource.provider.insert_order).to eq(2)
|
||||
end
|
||||
it 'understands offsets for editing rules at the middle' do
|
||||
resource = Puppet::Type.type(:firewall).new({ :name => '200 test', })
|
||||
allow(resource.provider.class).to receive(:instances).and_return(providers)
|
||||
expect(resource.provider.insert_order).to eq(2)
|
||||
end
|
||||
it 'understands offsets for adding rules to the end' do
|
||||
resource = Puppet::Type.type(:firewall).new({ :name => '301 test', })
|
||||
allow(resource.provider.class).to receive(:instances).and_return(providers)
|
||||
expect(resource.provider.insert_order).to eq(4)
|
||||
end
|
||||
it 'understands offsets for editing rules at the end' do
|
||||
resource = Puppet::Type.type(:firewall).new({ :name => '300 test', })
|
||||
allow(resource.provider.class).to receive(:instances).and_return(providers)
|
||||
expect(resource.provider.insert_order).to eq(3)
|
||||
end
|
||||
|
||||
context 'with unname rules between' do
|
||||
let(:iptables_save_output) { [
|
||||
'-A INPUT -s 8.0.0.2/32 -p tcp -m multiport --ports 100 -m comment --comment "100 test" -j ACCEPT',
|
||||
'-A INPUT -s 8.0.0.2/32 -p tcp -m multiport --ports 150 -m comment --comment "150 test" -j ACCEPT',
|
||||
'-A INPUT -s 8.0.0.3/32 -p tcp -m multiport --ports 200 -j ACCEPT',
|
||||
'-A INPUT -s 8.0.0.3/32 -p tcp -m multiport --ports 250 -j ACCEPT',
|
||||
'-A INPUT -s 8.0.0.4/32 -p tcp -m multiport --ports 300 -m comment --comment "300 test" -j ACCEPT',
|
||||
'-A INPUT -s 8.0.0.4/32 -p tcp -m multiport --ports 350 -m comment --comment "350 test" -j ACCEPT',
|
||||
] }
|
||||
it 'understands offsets for adding rules before unnamed rules' do
|
||||
resource = Puppet::Type.type(:firewall).new({ :name => '001 test', })
|
||||
allow(resource.provider.class).to receive(:instances).and_return(providers)
|
||||
expect(resource.provider.insert_order).to eq(1)
|
||||
end
|
||||
it 'understands offsets for editing rules before unnamed rules' do
|
||||
resource = Puppet::Type.type(:firewall).new({ :name => '100 test', })
|
||||
allow(resource.provider.class).to receive(:instances).and_return(providers)
|
||||
expect(resource.provider.insert_order).to eq(1)
|
||||
end
|
||||
it 'understands offsets for adding rules between managed rules' do
|
||||
resource = Puppet::Type.type(:firewall).new({ :name => '120 test', })
|
||||
allow(resource.provider.class).to receive(:instances).and_return(providers)
|
||||
expect(resource.provider.insert_order).to eq(2)
|
||||
end
|
||||
it 'understands offsets for adding rules between unnamed rules' do
|
||||
resource = Puppet::Type.type(:firewall).new({ :name => '151 test', })
|
||||
allow(resource.provider.class).to receive(:instances).and_return(providers)
|
||||
expect(resource.provider.insert_order).to eq(3)
|
||||
end
|
||||
it 'understands offsets for adding rules after unnamed rules' do
|
||||
resource = Puppet::Type.type(:firewall).new({ :name => '351 test', })
|
||||
allow(resource.provider.class).to receive(:instances).and_return(providers)
|
||||
expect(resource.provider.insert_order).to eq(7)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with unname rules before and after' do
|
||||
let(:iptables_save_output) { [
|
||||
'-A INPUT -s 8.0.0.3/32 -p tcp -m multiport --ports 050 -j ACCEPT',
|
||||
'-A INPUT -s 8.0.0.3/32 -p tcp -m multiport --ports 090 -j ACCEPT',
|
||||
'-A INPUT -s 8.0.0.2/32 -p tcp -m multiport --ports 100 -m comment --comment "100 test" -j ACCEPT',
|
||||
'-A INPUT -s 8.0.0.2/32 -p tcp -m multiport --ports 150 -m comment --comment "150 test" -j ACCEPT',
|
||||
'-A INPUT -s 8.0.0.3/32 -p tcp -m multiport --ports 200 -j ACCEPT',
|
||||
'-A INPUT -s 8.0.0.3/32 -p tcp -m multiport --ports 250 -j ACCEPT',
|
||||
'-A INPUT -s 8.0.0.4/32 -p tcp -m multiport --ports 300 -m comment --comment "300 test" -j ACCEPT',
|
||||
'-A INPUT -s 8.0.0.4/32 -p tcp -m multiport --ports 350 -m comment --comment "350 test" -j ACCEPT',
|
||||
'-A INPUT -s 8.0.0.5/32 -p tcp -m multiport --ports 400 -j ACCEPT',
|
||||
'-A INPUT -s 8.0.0.5/32 -p tcp -m multiport --ports 450 -j ACCEPT',
|
||||
] }
|
||||
it 'understands offsets for adding rules before unnamed rules' do
|
||||
resource = Puppet::Type.type(:firewall).new({ :name => '001 test', })
|
||||
allow(resource.provider.class).to receive(:instances).and_return(providers)
|
||||
expect(resource.provider.insert_order).to eq(1)
|
||||
end
|
||||
it 'understands offsets for editing rules before unnamed rules' do
|
||||
resource = Puppet::Type.type(:firewall).new({ :name => '100 test', })
|
||||
allow(resource.provider.class).to receive(:instances).and_return(providers)
|
||||
expect(resource.provider.insert_order).to eq(3)
|
||||
end
|
||||
it 'understands offsets for adding rules between managed rules' do
|
||||
resource = Puppet::Type.type(:firewall).new({ :name => '120 test', })
|
||||
allow(resource.provider.class).to receive(:instances).and_return(providers)
|
||||
expect(resource.provider.insert_order).to eq(4)
|
||||
end
|
||||
it 'understands offsets for adding rules between unnamed rules' do
|
||||
resource = Puppet::Type.type(:firewall).new({ :name => '151 test', })
|
||||
allow(resource.provider.class).to receive(:instances).and_return(providers)
|
||||
expect(resource.provider.insert_order).to eq(5)
|
||||
end
|
||||
it 'understands offsets for adding rules after unnamed rules' do
|
||||
resource = Puppet::Type.type(:firewall).new({ :name => '351 test', })
|
||||
allow(resource.provider.class).to receive(:instances).and_return(providers)
|
||||
expect(resource.provider.insert_order).to eq(9)
|
||||
end
|
||||
it 'understands offsets for adding rules at the end' do
|
||||
resource = Puppet::Type.type(:firewall).new({ :name => '950 test', })
|
||||
allow(resource.provider.class).to receive(:instances).and_return(providers)
|
||||
expect(resource.provider.insert_order).to eq(11)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Load in ruby hash for test fixtures.
|
||||
load 'spec/fixtures/iptables/conversion_hash.rb'
|
||||
|
||||
describe 'when converting rules to resources' do
|
||||
ARGS_TO_HASH.each do |test_name,data|
|
||||
describe "for test data '#{test_name}'" do
|
||||
let(:resource) { provider.rule_to_hash(data[:line], data[:table], 0) }
|
||||
|
||||
# If this option is enabled, make sure the parameters exactly match
|
||||
if data[:compare_all] then
|
||||
it "the parameter hash keys should be the same as returned by rules_to_hash" do
|
||||
expect(resource.keys).to match_array(data[:params].keys)
|
||||
end
|
||||
end
|
||||
|
||||
# Iterate across each parameter, creating an example for comparison
|
||||
data[:params].each do |param_name, param_value|
|
||||
it "the parameter '#{param_name.to_s}' should match #{param_value.inspect}" do
|
||||
# booleans get cludged to string "true"
|
||||
if param_value == true then
|
||||
expect(resource[param_name]).to be_true
|
||||
else
|
||||
expect(resource[param_name]).to eq(data[:params][param_name])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when working out general_args' do
|
||||
HASH_TO_ARGS.each do |test_name,data|
|
||||
describe "for test data '#{test_name}'" do
|
||||
let(:resource) { Puppet::Type.type(:firewall).new(data[:params]) }
|
||||
let(:provider) { Puppet::Type.type(:firewall).provider(:iptables) }
|
||||
let(:instance) { provider.new(resource) }
|
||||
|
||||
it 'general_args should be valid' do
|
||||
expect(instance.general_args.flatten).to eq(data[:args])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when converting rules without comments to resources' do
|
||||
let(:sample_rule) {
|
||||
'-A INPUT -s 1.1.1.1 -d 1.1.1.1 -p tcp -m multiport --dports 7061,7062 -m multiport --sports 7061,7062 -j ACCEPT'
|
||||
}
|
||||
let(:resource) { provider.rule_to_hash(sample_rule, 'filter', 0) }
|
||||
let(:instance) { provider.new(resource) }
|
||||
|
||||
it 'rule name contains a MD5 sum of the line' do
|
||||
expect(resource[:name]).to eq("9000 #{Digest::MD5.hexdigest(resource[:line])}")
|
||||
end
|
||||
|
||||
it 'parsed the rule arguments correctly' do
|
||||
expect(resource[:chain]).to eq('INPUT')
|
||||
expect(resource[:source]).to eq('1.1.1.1/32')
|
||||
expect(resource[:destination]).to eq('1.1.1.1/32')
|
||||
expect(resource[:proto]).to eq('tcp')
|
||||
expect(resource[:dport]).to eq(['7061', '7062'])
|
||||
expect(resource[:sport]).to eq(['7061', '7062'])
|
||||
expect(resource[:action]).to eq('accept')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when converting existing rules generates by system-config-firewall-tui to resources' do
|
||||
let(:sample_rule) {
|
||||
# as generated by iptables-save from rules created with system-config-firewall-tui
|
||||
'-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT'
|
||||
}
|
||||
let(:resource) { provider.rule_to_hash(sample_rule, 'filter', 0) }
|
||||
let(:instance) { provider.new(resource) }
|
||||
|
||||
it 'rule name contains a MD5 sum of the line' do
|
||||
expect(resource[:name]).to eq("9000 #{Digest::MD5.hexdigest(resource[:line])}")
|
||||
end
|
||||
|
||||
it 'parse arguments' do
|
||||
expect(resource[:chain]).to eq('INPUT')
|
||||
expect(resource[:proto]).to eq('tcp')
|
||||
expect(resource[:dport]).to eq(['22'])
|
||||
expect(resource[:state]).to eq(['NEW'])
|
||||
expect(resource[:action]).to eq('accept')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when creating resources' do
|
||||
let(:instance) { provider.new(resource) }
|
||||
|
||||
it 'insert_args should be an array' do
|
||||
expect(instance.insert_args.class).to eq(Array)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when modifying resources' do
|
||||
let(:instance) { provider.new(resource) }
|
||||
|
||||
it 'update_args should be an array' do
|
||||
expect(instance.update_args.class).to eq(Array)
|
||||
end
|
||||
|
||||
it 'fails when modifying the chain' do
|
||||
expect { instance.chain = "OUTPUT" }.to raise_error(/is not supported/)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when deleting resources' do
|
||||
let(:sample_rule) {
|
||||
'-A INPUT -s 1.1.1.1 -d 1.1.1.1 -p tcp -m multiport --dports 7061,7062 -m multiport --sports 7061,7062 -j ACCEPT'
|
||||
}
|
||||
let(:resource) { provider.rule_to_hash(sample_rule, 'filter', 0) }
|
||||
let(:instance) { provider.new(resource) }
|
||||
|
||||
it 'resource[:line] looks like the original rule' do
|
||||
resource[:line] == sample_rule
|
||||
end
|
||||
|
||||
it 'delete_args is an array' do
|
||||
expect(instance.delete_args.class).to eq(Array)
|
||||
end
|
||||
|
||||
it 'delete_args is the same as the rule string when joined' do
|
||||
expect(instance.delete_args.join(' ')).to eq(sample_rule.gsub(/\-A/,
|
||||
'-t filter -D'))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'ip6tables provider' do
|
||||
let(:provider6) { Puppet::Type.type(:firewall).provider(:ip6tables) }
|
||||
let(:resource) {
|
||||
Puppet::Type.type(:firewall).new({
|
||||
:name => '000 test foo',
|
||||
:action => 'accept',
|
||||
:provider => "ip6tables",
|
||||
})
|
||||
}
|
||||
|
||||
before :each do
|
||||
allow(Puppet::Type::Firewall).to receive(:ip6tables).and_return provider6
|
||||
allow(provider6).to receive(:command).with(:ip6tables_save).and_return "/sbin/ip6tables-save"
|
||||
|
||||
# Stub iptables version
|
||||
allow(Facter.fact(:ip6tables_version)).to receive(:value).and_return '1.4.7'
|
||||
|
||||
allow(Puppet::Util::Execution).to receive(:execute).and_return ''
|
||||
allow(Puppet::Util).to receive(:which).with("ip6tables-save").
|
||||
and_return "/sbin/ip6tables-save"
|
||||
end
|
||||
|
||||
it 'should be able to get a list of existing rules' do
|
||||
provider6.instances.each do |rule|
|
||||
rule.should be_instance_of(provider6)
|
||||
rule.properties[:provider6].to_s.should == provider6.name.to_s
|
||||
end
|
||||
end
|
||||
|
||||
it 'should ignore lines with fatal errors' do
|
||||
allow(Puppet::Util::Execution).to receive(:execute).with(['/sbin/ip6tables-save']).
|
||||
and_return("FATAL: Could not load /lib/modules/2.6.18-028stab095.1/modules.dep: No such file or directory")
|
||||
provider6.instances.length.should == 0
|
||||
end
|
||||
|
||||
# Load in ruby hash for test fixtures.
|
||||
load 'spec/fixtures/ip6tables/conversion_hash.rb'
|
||||
|
||||
describe 'when converting rules to resources' do
|
||||
ARGS_TO_HASH6.each do |test_name,data|
|
||||
describe "for test data '#{test_name}'" do
|
||||
let(:resource) { provider6.rule_to_hash(data[:line], data[:table], 0) }
|
||||
|
||||
# If this option is enabled, make sure the parameters exactly match
|
||||
if data[:compare_all] then
|
||||
it "the parameter hash keys should be the same as returned by rules_to_hash" do
|
||||
resource.keys.should =~ data[:params].keys
|
||||
end
|
||||
end
|
||||
|
||||
# Iterate across each parameter, creating an example for comparison
|
||||
data[:params].each do |param_name, param_value|
|
||||
it "the parameter '#{param_name.to_s}' should match #{param_value.inspect}" do
|
||||
resource[param_name].should == data[:params][param_name]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when working out general_args' do
|
||||
HASH_TO_ARGS6.each do |test_name,data|
|
||||
describe "for test data '#{test_name}'" do
|
||||
let(:resource) { Puppet::Type.type(:firewall).new(data[:params]) }
|
||||
let(:provider6) { Puppet::Type.type(:firewall).provider(:ip6tables) }
|
||||
let(:instance) { provider6.new(resource) }
|
||||
|
||||
it 'general_args should be valid' do
|
||||
instance.general_args.flatten.should == data[:args]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
650
modules/firewall/spec/unit/puppet/type/firewall_spec.rb
Executable file
650
modules/firewall/spec/unit/puppet/type/firewall_spec.rb
Executable file
|
@ -0,0 +1,650 @@
|
|||
#!/usr/bin/env rspec
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
firewall = Puppet::Type.type(:firewall)
|
||||
|
||||
describe firewall do
|
||||
before :each do
|
||||
@class = firewall
|
||||
@provider = double 'provider'
|
||||
allow(@provider).to receive(:name).and_return(:iptables)
|
||||
allow(Puppet::Type::Firewall).to receive(:defaultprovider).and_return @provider
|
||||
|
||||
@resource = @class.new({:name => '000 test foo'})
|
||||
|
||||
# Stub iptables version
|
||||
allow(Facter.fact(:iptables_version)).to receive(:value).and_return('1.4.2')
|
||||
allow(Facter.fact(:ip6tables_version)).to receive(:value).and_return('1.4.2')
|
||||
|
||||
# Stub confine facts
|
||||
allow(Facter.fact(:kernel)).to receive(:value).and_return('Linux')
|
||||
allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('Debian')
|
||||
end
|
||||
|
||||
it 'should have :name be its namevar' do
|
||||
@class.key_attributes.should == [:name]
|
||||
end
|
||||
|
||||
describe ':name' do
|
||||
it 'should accept a name' do
|
||||
@resource[:name] = '000-test-foo'
|
||||
@resource[:name].should == '000-test-foo'
|
||||
end
|
||||
|
||||
it 'should not accept a name with non-ASCII chars' do
|
||||
lambda { @resource[:name] = '%*#^(#$' }.should raise_error(Puppet::Error)
|
||||
end
|
||||
end
|
||||
|
||||
describe ':action' do
|
||||
it "should have no default" do
|
||||
res = @class.new(:name => "000 test")
|
||||
res.parameters[:action].should == nil
|
||||
end
|
||||
|
||||
[:accept, :drop, :reject].each do |action|
|
||||
it "should accept value #{action}" do
|
||||
@resource[:action] = action
|
||||
@resource[:action].should == action
|
||||
end
|
||||
end
|
||||
|
||||
it 'should fail when value is not recognized' do
|
||||
lambda { @resource[:action] = 'not valid' }.should raise_error(Puppet::Error)
|
||||
end
|
||||
end
|
||||
|
||||
describe ':chain' do
|
||||
[:INPUT, :FORWARD, :OUTPUT, :PREROUTING, :POSTROUTING].each do |chain|
|
||||
it "should accept chain value #{chain}" do
|
||||
@resource[:chain] = chain
|
||||
@resource[:chain].should == chain
|
||||
end
|
||||
end
|
||||
|
||||
it 'should fail when the chain value is not recognized' do
|
||||
lambda { @resource[:chain] = 'not valid' }.should raise_error(Puppet::Error)
|
||||
end
|
||||
end
|
||||
|
||||
describe ':table' do
|
||||
[:nat, :mangle, :filter, :raw].each do |table|
|
||||
it "should accept table value #{table}" do
|
||||
@resource[:table] = table
|
||||
@resource[:table].should == table
|
||||
end
|
||||
end
|
||||
|
||||
it "should fail when table value is not recognized" do
|
||||
lambda { @resource[:table] = 'not valid' }.should raise_error(Puppet::Error)
|
||||
end
|
||||
end
|
||||
|
||||
describe ':proto' do
|
||||
[:tcp, :udp, :icmp, :esp, :ah, :vrrp, :igmp, :ipencap, :ospf, :gre, :all].each do |proto|
|
||||
it "should accept proto value #{proto}" do
|
||||
@resource[:proto] = proto
|
||||
@resource[:proto].should == proto
|
||||
end
|
||||
end
|
||||
|
||||
it "should fail when proto value is not recognized" do
|
||||
lambda { @resource[:proto] = 'foo' }.should raise_error(Puppet::Error)
|
||||
end
|
||||
end
|
||||
|
||||
describe ':jump' do
|
||||
it "should have no default" do
|
||||
res = @class.new(:name => "000 test")
|
||||
res.parameters[:jump].should == nil
|
||||
end
|
||||
|
||||
['QUEUE', 'RETURN', 'DNAT', 'SNAT', 'LOG', 'MASQUERADE', 'REDIRECT', 'MARK'].each do |jump|
|
||||
it "should accept jump value #{jump}" do
|
||||
@resource[:jump] = jump
|
||||
@resource[:jump].should == jump
|
||||
end
|
||||
end
|
||||
|
||||
['ACCEPT', 'DROP', 'REJECT'].each do |jump|
|
||||
it "should now fail when value #{jump}" do
|
||||
lambda { @resource[:jump] = jump }.should raise_error(Puppet::Error)
|
||||
end
|
||||
end
|
||||
|
||||
it "should fail when jump value is not recognized" do
|
||||
lambda { @resource[:jump] = '%^&*' }.should raise_error(Puppet::Error)
|
||||
end
|
||||
end
|
||||
|
||||
[:source, :destination].each do |addr|
|
||||
describe addr do
|
||||
it "should accept a #{addr} as a string" do
|
||||
@resource[addr] = '127.0.0.1'
|
||||
@resource[addr].should == '127.0.0.1/32'
|
||||
end
|
||||
['0.0.0.0/0', '::/0'].each do |prefix|
|
||||
it "should be nil for zero prefix length address #{prefix}" do
|
||||
@resource[addr] = prefix
|
||||
@resource[addr].should == nil
|
||||
end
|
||||
end
|
||||
it "should accept a negated #{addr} as a string" do
|
||||
@resource[addr] = '! 127.0.0.1'
|
||||
@resource[addr].should == '! 127.0.0.1/32'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
[:dport, :sport].each do |port|
|
||||
describe port do
|
||||
it "should accept a #{port} as string" do
|
||||
@resource[port] = '22'
|
||||
@resource[port].should == ['22']
|
||||
end
|
||||
|
||||
it "should accept a #{port} as an array" do
|
||||
@resource[port] = ['22','23']
|
||||
@resource[port].should == ['22','23']
|
||||
end
|
||||
|
||||
it "should accept a #{port} as a number" do
|
||||
@resource[port] = 22
|
||||
@resource[port].should == ['22']
|
||||
end
|
||||
|
||||
it "should accept a #{port} as a hyphen separated range" do
|
||||
@resource[port] = ['22-1000']
|
||||
@resource[port].should == ['22-1000']
|
||||
end
|
||||
|
||||
it "should accept a #{port} as a combination of arrays of single and " \
|
||||
"hyphen separated ranges" do
|
||||
|
||||
@resource[port] = ['22-1000','33','3000-4000']
|
||||
@resource[port].should == ['22-1000','33','3000-4000']
|
||||
end
|
||||
|
||||
it "should convert a port name for #{port} to its number" do
|
||||
@resource[port] = 'ssh'
|
||||
@resource[port].should == ['22']
|
||||
end
|
||||
|
||||
it "should not accept something invalid for #{port}" do
|
||||
expect { @resource[port] = 'something odd' }.to raise_error(Puppet::Error, /^Parameter .+ failed.+Munging failed for value ".+" in class .+: no such service/)
|
||||
end
|
||||
|
||||
it "should not accept something invalid in an array for #{port}" do
|
||||
expect { @resource[port] = ['something odd','something even odder'] }.to raise_error(Puppet::Error, /^Parameter .+ failed.+Munging failed for value ".+" in class .+: no such service/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
[:dst_type, :src_type].each do |addrtype|
|
||||
describe addrtype do
|
||||
it "should have no default" do
|
||||
res = @class.new(:name => "000 test")
|
||||
res.parameters[addrtype].should == nil
|
||||
end
|
||||
end
|
||||
|
||||
[:UNSPEC, :UNICAST, :LOCAL, :BROADCAST, :ANYCAST, :MULTICAST, :BLACKHOLE,
|
||||
:UNREACHABLE, :PROHIBIT, :THROW, :NAT, :XRESOLVE].each do |type|
|
||||
it "should accept #{addrtype} value #{type}" do
|
||||
@resource[addrtype] = type
|
||||
@resource[addrtype].should == type
|
||||
end
|
||||
end
|
||||
|
||||
it "should fail when #{addrtype} value is not recognized" do
|
||||
lambda { @resource[addrtype] = 'foo' }.should raise_error(Puppet::Error)
|
||||
end
|
||||
end
|
||||
|
||||
[:iniface, :outiface].each do |iface|
|
||||
describe iface do
|
||||
it "should accept #{iface} value as a string" do
|
||||
@resource[iface] = 'eth1'
|
||||
@resource[iface].should == 'eth1'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
[:tosource, :todest].each do |addr|
|
||||
describe addr do
|
||||
it "should accept #{addr} value as a string" do
|
||||
@resource[addr] = '127.0.0.1'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe ':log_level' do
|
||||
values = {
|
||||
'panic' => '0',
|
||||
'alert' => '1',
|
||||
'crit' => '2',
|
||||
'err' => '3',
|
||||
'warn' => '4',
|
||||
'warning' => '4',
|
||||
'not' => '5',
|
||||
'notice' => '5',
|
||||
'info' => '6',
|
||||
'debug' => '7'
|
||||
}
|
||||
|
||||
values.each do |k,v|
|
||||
it {
|
||||
@resource[:log_level] = k
|
||||
@resource[:log_level].should == v
|
||||
}
|
||||
|
||||
it {
|
||||
@resource[:log_level] = 3
|
||||
@resource[:log_level].should == 3
|
||||
}
|
||||
|
||||
it { lambda { @resource[:log_level] = 'foo' }.should raise_error(Puppet::Error) }
|
||||
end
|
||||
end
|
||||
|
||||
describe ':icmp' do
|
||||
icmp_codes = {
|
||||
:iptables => {
|
||||
'0' => 'echo-reply',
|
||||
'3' => 'destination-unreachable',
|
||||
'4' => 'source-quench',
|
||||
'6' => 'redirect',
|
||||
'8' => 'echo-request',
|
||||
'9' => 'router-advertisement',
|
||||
'10' => 'router-solicitation',
|
||||
'11' => 'time-exceeded',
|
||||
'12' => 'parameter-problem',
|
||||
'13' => 'timestamp-request',
|
||||
'14' => 'timestamp-reply',
|
||||
'17' => 'address-mask-request',
|
||||
'18' => 'address-mask-reply'
|
||||
},
|
||||
:ip6tables => {
|
||||
'1' => 'destination-unreachable',
|
||||
'3' => 'time-exceeded',
|
||||
'4' => 'parameter-problem',
|
||||
'128' => 'echo-request',
|
||||
'129' => 'echo-reply',
|
||||
'133' => 'router-solicitation',
|
||||
'134' => 'router-advertisement',
|
||||
'137' => 'redirect'
|
||||
}
|
||||
}
|
||||
icmp_codes.each do |provider, values|
|
||||
describe provider do
|
||||
values.each do |k,v|
|
||||
it 'should convert icmp string to number' do
|
||||
@resource[:provider] = provider
|
||||
@resource[:provider].should == provider
|
||||
@resource[:icmp] = v
|
||||
@resource[:icmp].should == k
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'should accept values as integers' do
|
||||
@resource[:icmp] = 9
|
||||
@resource[:icmp].should == 9
|
||||
end
|
||||
|
||||
it 'should fail if icmp type is "any"' do
|
||||
lambda { @resource[:icmp] = 'any' }.should raise_error(Puppet::Error)
|
||||
end
|
||||
|
||||
it 'should fail if icmp type cannot be mapped to a numeric' do
|
||||
lambda { @resource[:icmp] = 'foo' }.should raise_error(Puppet::Error)
|
||||
end
|
||||
end
|
||||
|
||||
describe ':state' do
|
||||
it 'should accept value as a string' do
|
||||
@resource[:state] = :INVALID
|
||||
@resource[:state].should == [:INVALID]
|
||||
end
|
||||
|
||||
it 'should accept value as an array' do
|
||||
@resource[:state] = [:INVALID, :NEW]
|
||||
@resource[:state].should == [:INVALID, :NEW]
|
||||
end
|
||||
|
||||
it 'should sort values alphabetically' do
|
||||
@resource[:state] = [:NEW, :ESTABLISHED]
|
||||
@resource[:state].should == [:ESTABLISHED, :NEW]
|
||||
end
|
||||
end
|
||||
|
||||
describe ':ctstate' do
|
||||
it 'should accept value as a string' do
|
||||
@resource[:ctstate] = :INVALID
|
||||
@resource[:ctstate].should == [:INVALID]
|
||||
end
|
||||
|
||||
it 'should accept value as an array' do
|
||||
@resource[:ctstate] = [:INVALID, :NEW]
|
||||
@resource[:ctstate].should == [:INVALID, :NEW]
|
||||
end
|
||||
|
||||
it 'should sort values alphabetically' do
|
||||
@resource[:ctstate] = [:NEW, :ESTABLISHED]
|
||||
@resource[:ctstate].should == [:ESTABLISHED, :NEW]
|
||||
end
|
||||
end
|
||||
|
||||
describe ':burst' do
|
||||
it 'should accept numeric values' do
|
||||
@resource[:burst] = 12
|
||||
@resource[:burst].should == 12
|
||||
end
|
||||
|
||||
it 'should fail if value is not numeric' do
|
||||
lambda { @resource[:burst] = 'foo' }.should raise_error(Puppet::Error)
|
||||
end
|
||||
end
|
||||
|
||||
describe ':recent' do
|
||||
['set', 'update', 'rcheck', 'remove'].each do |recent|
|
||||
it "should accept recent value #{recent}" do
|
||||
@resource[:recent] = recent
|
||||
@resource[:recent].should == "--#{recent}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe ':action and :jump' do
|
||||
it 'should allow only 1 to be set at a time' do
|
||||
expect {
|
||||
@class.new(
|
||||
:name => "001-test",
|
||||
:action => "accept",
|
||||
:jump => "custom_chain"
|
||||
)
|
||||
}.to raise_error(Puppet::Error, /Only one of the parameters 'action' and 'jump' can be set$/)
|
||||
end
|
||||
end
|
||||
describe ':gid and :uid' do
|
||||
it 'should allow me to set uid' do
|
||||
@resource[:uid] = 'root'
|
||||
@resource[:uid].should == 'root'
|
||||
end
|
||||
it 'should allow me to set uid as an array, and silently hide my error' do
|
||||
@resource[:uid] = ['root', 'bobby']
|
||||
@resource[:uid].should == 'root'
|
||||
end
|
||||
it 'should allow me to set gid' do
|
||||
@resource[:gid] = 'root'
|
||||
@resource[:gid].should == 'root'
|
||||
end
|
||||
it 'should allow me to set gid as an array, and silently hide my error' do
|
||||
@resource[:gid] = ['root', 'bobby']
|
||||
@resource[:gid].should == 'root'
|
||||
end
|
||||
end
|
||||
|
||||
describe ':set_mark' do
|
||||
['1.3.2', '1.4.2'].each do |iptables_version|
|
||||
describe "with iptables #{iptables_version}" do
|
||||
before {
|
||||
Facter.clear
|
||||
allow(Facter.fact(:iptables_version)).to receive(:value).and_return iptables_version
|
||||
allow(Facter.fact(:ip6tables_version)).to receive(:value).and_return iptables_version
|
||||
}
|
||||
|
||||
if iptables_version == '1.3.2'
|
||||
it 'should allow me to set set-mark without mask' do
|
||||
@resource[:set_mark] = '0x3e8'
|
||||
@resource[:set_mark].should == '0x3e8'
|
||||
end
|
||||
it 'should convert int to hex without mask' do
|
||||
@resource[:set_mark] = '1000'
|
||||
@resource[:set_mark].should == '0x3e8'
|
||||
end
|
||||
it 'should fail if mask is present' do
|
||||
lambda { @resource[:set_mark] = '0x3e8/0xffffffff'}.should raise_error(
|
||||
Puppet::Error, /iptables version #{iptables_version} does not support masks on MARK rules$/
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
if iptables_version == '1.4.2'
|
||||
it 'should allow me to set set-mark with mask' do
|
||||
@resource[:set_mark] = '0x3e8/0xffffffff'
|
||||
@resource[:set_mark].should == '0x3e8/0xffffffff'
|
||||
end
|
||||
it 'should convert int to hex and add a 32 bit mask' do
|
||||
@resource[:set_mark] = '1000'
|
||||
@resource[:set_mark].should == '0x3e8/0xffffffff'
|
||||
end
|
||||
it 'should add a 32 bit mask' do
|
||||
@resource[:set_mark] = '0x32'
|
||||
@resource[:set_mark].should == '0x32/0xffffffff'
|
||||
end
|
||||
it 'should use the mask provided' do
|
||||
@resource[:set_mark] = '0x32/0x4'
|
||||
@resource[:set_mark].should == '0x32/0x4'
|
||||
end
|
||||
it 'should use the mask provided and convert int to hex' do
|
||||
@resource[:set_mark] = '1000/0x4'
|
||||
@resource[:set_mark].should == '0x3e8/0x4'
|
||||
end
|
||||
it 'should fail if mask value is more than 32 bits' do
|
||||
lambda { @resource[:set_mark] = '1/4294967296'}.should raise_error(
|
||||
Puppet::Error, /MARK mask must be integer or hex between 0 and 0xffffffff$/
|
||||
)
|
||||
end
|
||||
it 'should fail if mask is malformed' do
|
||||
lambda { @resource[:set_mark] = '1000/0xq4'}.should raise_error(
|
||||
Puppet::Error, /MARK mask must be integer or hex between 0 and 0xffffffff$/
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
['/', '1000/', 'pwnie'].each do |bad_mark|
|
||||
it "should fail with malformed mark '#{bad_mark}'" do
|
||||
lambda { @resource[:set_mark] = bad_mark}.should raise_error(Puppet::Error)
|
||||
end
|
||||
end
|
||||
it 'should fail if mark value is more than 32 bits' do
|
||||
lambda { @resource[:set_mark] = '4294967296'}.should raise_error(
|
||||
Puppet::Error, /MARK value must be integer or hex between 0 and 0xffffffff$/
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
[:chain, :jump].each do |param|
|
||||
describe param do
|
||||
it 'should autorequire fwchain when table and provider are undefined' do
|
||||
@resource[param] = 'FOO'
|
||||
@resource[:table].should == :filter
|
||||
@resource[:provider].should == :iptables
|
||||
|
||||
chain = Puppet::Type.type(:firewallchain).new(:name => 'FOO:filter:IPv4')
|
||||
catalog = Puppet::Resource::Catalog.new
|
||||
catalog.add_resource @resource
|
||||
catalog.add_resource chain
|
||||
rel = @resource.autorequire[0]
|
||||
rel.source.ref.should == chain.ref
|
||||
rel.target.ref.should == @resource.ref
|
||||
end
|
||||
|
||||
it 'should autorequire fwchain when table is undefined and provider is ip6tables' do
|
||||
@resource[param] = 'FOO'
|
||||
@resource[:table].should == :filter
|
||||
@resource[:provider] = :ip6tables
|
||||
|
||||
chain = Puppet::Type.type(:firewallchain).new(:name => 'FOO:filter:IPv6')
|
||||
catalog = Puppet::Resource::Catalog.new
|
||||
catalog.add_resource @resource
|
||||
catalog.add_resource chain
|
||||
rel = @resource.autorequire[0]
|
||||
rel.source.ref.should == chain.ref
|
||||
rel.target.ref.should == @resource.ref
|
||||
end
|
||||
|
||||
it 'should autorequire fwchain when table is raw and provider is undefined' do
|
||||
@resource[param] = 'FOO'
|
||||
@resource[:table] = :raw
|
||||
@resource[:provider].should == :iptables
|
||||
|
||||
chain = Puppet::Type.type(:firewallchain).new(:name => 'FOO:raw:IPv4')
|
||||
catalog = Puppet::Resource::Catalog.new
|
||||
catalog.add_resource @resource
|
||||
catalog.add_resource chain
|
||||
rel = @resource.autorequire[0]
|
||||
rel.source.ref.should == chain.ref
|
||||
rel.target.ref.should == @resource.ref
|
||||
end
|
||||
|
||||
it 'should autorequire fwchain when table is raw and provider is ip6tables' do
|
||||
@resource[param] = 'FOO'
|
||||
@resource[:table] = :raw
|
||||
@resource[:provider] = :ip6tables
|
||||
|
||||
chain = Puppet::Type.type(:firewallchain).new(:name => 'FOO:raw:IPv6')
|
||||
catalog = Puppet::Resource::Catalog.new
|
||||
catalog.add_resource @resource
|
||||
catalog.add_resource chain
|
||||
rel = @resource.autorequire[0]
|
||||
rel.source.ref.should == chain.ref
|
||||
rel.target.ref.should == @resource.ref
|
||||
end
|
||||
|
||||
# test where autorequire is still needed (table != filter)
|
||||
['INPUT', 'OUTPUT', 'FORWARD'].each do |test_chain|
|
||||
it "should autorequire fwchain #{test_chain} when table is mangle and provider is undefined" do
|
||||
@resource[param] = test_chain
|
||||
@resource[:table] = :mangle
|
||||
@resource[:provider].should == :iptables
|
||||
|
||||
chain = Puppet::Type.type(:firewallchain).new(:name => "#{test_chain}:mangle:IPv4")
|
||||
catalog = Puppet::Resource::Catalog.new
|
||||
catalog.add_resource @resource
|
||||
catalog.add_resource chain
|
||||
rel = @resource.autorequire[0]
|
||||
rel.source.ref.should == chain.ref
|
||||
rel.target.ref.should == @resource.ref
|
||||
end
|
||||
|
||||
it "should autorequire fwchain #{test_chain} when table is mangle and provider is ip6tables" do
|
||||
@resource[param] = test_chain
|
||||
@resource[:table] = :mangle
|
||||
@resource[:provider] = :ip6tables
|
||||
|
||||
chain = Puppet::Type.type(:firewallchain).new(:name => "#{test_chain}:mangle:IPv6")
|
||||
catalog = Puppet::Resource::Catalog.new
|
||||
catalog.add_resource @resource
|
||||
catalog.add_resource chain
|
||||
rel = @resource.autorequire[0]
|
||||
rel.source.ref.should == chain.ref
|
||||
rel.target.ref.should == @resource.ref
|
||||
end
|
||||
end
|
||||
|
||||
# test of case where autorequire should not happen
|
||||
['INPUT', 'OUTPUT', 'FORWARD'].each do |test_chain|
|
||||
|
||||
it "should not autorequire fwchain #{test_chain} when table and provider are undefined" do
|
||||
@resource[param] = test_chain
|
||||
@resource[:table].should == :filter
|
||||
@resource[:provider].should == :iptables
|
||||
|
||||
chain = Puppet::Type.type(:firewallchain).new(:name => "#{test_chain}:filter:IPv4")
|
||||
catalog = Puppet::Resource::Catalog.new
|
||||
catalog.add_resource @resource
|
||||
catalog.add_resource chain
|
||||
rel = @resource.autorequire[0]
|
||||
rel.should == nil
|
||||
end
|
||||
|
||||
it "should not autorequire fwchain #{test_chain} when table is undefined and provider is ip6tables" do
|
||||
@resource[param] = test_chain
|
||||
@resource[:table].should == :filter
|
||||
@resource[:provider] = :ip6tables
|
||||
|
||||
chain = Puppet::Type.type(:firewallchain).new(:name => "#{test_chain}:filter:IPv6")
|
||||
catalog = Puppet::Resource::Catalog.new
|
||||
catalog.add_resource @resource
|
||||
catalog.add_resource chain
|
||||
rel = @resource.autorequire[0]
|
||||
rel.should == nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe ":chain and :jump" do
|
||||
it 'should autorequire independent fwchains' do
|
||||
@resource[:chain] = 'FOO'
|
||||
@resource[:jump] = 'BAR'
|
||||
@resource[:table].should == :filter
|
||||
@resource[:provider].should == :iptables
|
||||
|
||||
chain_foo = Puppet::Type.type(:firewallchain).new(:name => 'FOO:filter:IPv4')
|
||||
chain_bar = Puppet::Type.type(:firewallchain).new(:name => 'BAR:filter:IPv4')
|
||||
catalog = Puppet::Resource::Catalog.new
|
||||
catalog.add_resource @resource
|
||||
catalog.add_resource chain_foo
|
||||
catalog.add_resource chain_bar
|
||||
rel = @resource.autorequire
|
||||
rel[0].source.ref.should == chain_foo.ref
|
||||
rel[0].target.ref.should == @resource.ref
|
||||
rel[1].source.ref.should == chain_bar.ref
|
||||
rel[1].target.ref.should == @resource.ref
|
||||
end
|
||||
end
|
||||
|
||||
describe ':pkttype' do
|
||||
[:multicast, :broadcast, :unicast].each do |pkttype|
|
||||
it "should accept pkttype value #{pkttype}" do
|
||||
@resource[:pkttype] = pkttype
|
||||
@resource[:pkttype].should == pkttype
|
||||
end
|
||||
end
|
||||
|
||||
it 'should fail when the pkttype value is not recognized' do
|
||||
lambda { @resource[:pkttype] = 'not valid' }.should raise_error(Puppet::Error)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'autorequire packages' do
|
||||
[:iptables, :ip6tables].each do |provider|
|
||||
it "provider #{provider} should autorequire package iptables" do
|
||||
@resource[:provider] = provider
|
||||
@resource[:provider].should == provider
|
||||
package = Puppet::Type.type(:package).new(:name => 'iptables')
|
||||
catalog = Puppet::Resource::Catalog.new
|
||||
catalog.add_resource @resource
|
||||
catalog.add_resource package
|
||||
rel = @resource.autorequire[0]
|
||||
rel.source.ref.should == package.ref
|
||||
rel.target.ref.should == @resource.ref
|
||||
end
|
||||
|
||||
it "provider #{provider} should autorequire packages iptables and iptables-persistent" do
|
||||
@resource[:provider] = provider
|
||||
@resource[:provider].should == provider
|
||||
packages = [
|
||||
Puppet::Type.type(:package).new(:name => 'iptables'),
|
||||
Puppet::Type.type(:package).new(:name => 'iptables-persistent')
|
||||
]
|
||||
catalog = Puppet::Resource::Catalog.new
|
||||
catalog.add_resource @resource
|
||||
packages.each do |package|
|
||||
catalog.add_resource package
|
||||
end
|
||||
packages.zip(@resource.autorequire) do |package, rel|
|
||||
rel.source.ref.should == package.ref
|
||||
rel.target.ref.should == @resource.ref
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
185
modules/firewall/spec/unit/puppet/type/firewallchain_spec.rb
Executable file
185
modules/firewall/spec/unit/puppet/type/firewallchain_spec.rb
Executable file
|
@ -0,0 +1,185 @@
|
|||
#!/usr/bin/env rspec
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
firewallchain = Puppet::Type.type(:firewallchain)
|
||||
|
||||
describe firewallchain do
|
||||
before(:each) do
|
||||
# Stub confine facts
|
||||
allow(Facter.fact(:kernel)).to receive(:value).and_return('Linux')
|
||||
allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('Debian')
|
||||
end
|
||||
let(:klass) { firewallchain }
|
||||
let(:provider) {
|
||||
prov = double 'provider'
|
||||
allow(prov).to receive(:name).and_return(:iptables_chain)
|
||||
prov
|
||||
}
|
||||
let(:resource) {
|
||||
allow(Puppet::Type::Firewallchain).to receive(:defaultprovider).and_return provider
|
||||
klass.new({:name => 'INPUT:filter:IPv4', :policy => :accept })
|
||||
}
|
||||
|
||||
it 'should have :name be its namevar' do
|
||||
klass.key_attributes.should == [:name]
|
||||
end
|
||||
|
||||
describe ':name' do
|
||||
{'nat' => ['PREROUTING', 'POSTROUTING', 'INPUT', 'OUTPUT'],
|
||||
'mangle' => [ 'PREROUTING', 'POSTROUTING', 'INPUT', 'FORWARD', 'OUTPUT' ],
|
||||
'filter' => ['INPUT','OUTPUT','FORWARD'],
|
||||
'raw' => [ 'PREROUTING', 'OUTPUT'],
|
||||
'broute' => ['BROUTING']
|
||||
}.each_pair do |table, allowedinternalchains|
|
||||
['IPv4', 'IPv6', 'ethernet'].each do |protocol|
|
||||
[ 'test', '$5()*&%\'"^$09):' ].each do |chainname|
|
||||
name = "#{chainname}:#{table}:#{protocol}"
|
||||
if table == 'nat' && protocol == 'IPv6'
|
||||
it "should fail #{name}" do
|
||||
expect { resource[:name] = name }.to raise_error(Puppet::Error)
|
||||
end
|
||||
elsif protocol != 'ethernet' && table == 'broute'
|
||||
it "should fail #{name}" do
|
||||
expect { resource[:name] = name }.to raise_error(Puppet::Error)
|
||||
end
|
||||
else
|
||||
it "should accept name #{name}" do
|
||||
resource[:name] = name
|
||||
resource[:name].should == name
|
||||
end
|
||||
end
|
||||
end # chainname
|
||||
end # protocol
|
||||
|
||||
[ 'PREROUTING', 'POSTROUTING', 'BROUTING', 'INPUT', 'FORWARD', 'OUTPUT' ].each do |internalchain|
|
||||
name = internalchain + ':' + table + ':'
|
||||
if internalchain == 'BROUTING'
|
||||
name += 'ethernet'
|
||||
elsif table == 'nat'
|
||||
name += 'IPv4'
|
||||
else
|
||||
name += 'IPv4'
|
||||
end
|
||||
if allowedinternalchains.include? internalchain
|
||||
it "should allow #{name}" do
|
||||
resource[:name] = name
|
||||
resource[:name].should == name
|
||||
end
|
||||
else
|
||||
it "should fail #{name}" do
|
||||
expect { resource[:name] = name }.to raise_error(Puppet::Error)
|
||||
end
|
||||
end
|
||||
end # internalchain
|
||||
|
||||
end # table, allowedinternalchainnames
|
||||
|
||||
it 'should fail with invalid table names' do
|
||||
expect { resource[:name] = 'wrongtablename:test:IPv4' }.to raise_error(Puppet::Error)
|
||||
end
|
||||
|
||||
it 'should fail with invalid protocols names' do
|
||||
expect { resource[:name] = 'test:filter:IPv5' }.to raise_error(Puppet::Error)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe ':policy' do
|
||||
|
||||
[:accept, :drop, :queue, :return].each do |policy|
|
||||
it "should accept policy #{policy}" do
|
||||
resource[:policy] = policy
|
||||
resource[:policy].should == policy
|
||||
end
|
||||
end
|
||||
|
||||
it 'should fail when value is not recognized' do
|
||||
expect { resource[:policy] = 'not valid' }.to raise_error(Puppet::Error)
|
||||
end
|
||||
|
||||
[:accept, :drop, :queue, :return].each do |policy|
|
||||
it "non-inbuilt chains should not accept policy #{policy}" do
|
||||
expect { klass.new({:name => 'testchain:filter:IPv4', :policy => policy }) }.to raise_error(Puppet::Error)
|
||||
end
|
||||
it "non-inbuilt chains can accept policies on protocol = ethernet (policy #{policy})" do
|
||||
klass.new({:name => 'testchain:filter:ethernet', :policy => policy })
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe 'autorequire packages' do
|
||||
it "provider iptables_chain should autorequire package iptables" do
|
||||
resource[:provider].should == :iptables_chain
|
||||
package = Puppet::Type.type(:package).new(:name => 'iptables')
|
||||
catalog = Puppet::Resource::Catalog.new
|
||||
catalog.add_resource resource
|
||||
catalog.add_resource package
|
||||
rel = resource.autorequire[0]
|
||||
rel.source.ref.should == package.ref
|
||||
rel.target.ref.should == resource.ref
|
||||
end
|
||||
|
||||
it "provider iptables_chain should autorequire packages iptables and iptables-persistent" do
|
||||
resource[:provider].should == :iptables_chain
|
||||
packages = [
|
||||
Puppet::Type.type(:package).new(:name => 'iptables'),
|
||||
Puppet::Type.type(:package).new(:name => 'iptables-persistent')
|
||||
]
|
||||
catalog = Puppet::Resource::Catalog.new
|
||||
catalog.add_resource resource
|
||||
packages.each do |package|
|
||||
catalog.add_resource package
|
||||
end
|
||||
packages.zip(resource.autorequire) do |package, rel|
|
||||
rel.source.ref.should == package.ref
|
||||
rel.target.ref.should == resource.ref
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'purge iptables rules' do
|
||||
before(:each) do
|
||||
allow(Puppet::Type.type(:firewall).provider(:iptables)).to receive(:iptables_save).and_return(<<EOS
|
||||
# Completed on Sun Jan 5 19:30:21 2014
|
||||
# Generated by iptables-save v1.4.12 on Sun Jan 5 19:30:21 2014
|
||||
*filter
|
||||
:INPUT DROP [0:0]
|
||||
:FORWARD DROP [0:0]
|
||||
:OUTPUT ACCEPT [0:0]
|
||||
:LOCAL_FORWARD - [0:0]
|
||||
:LOCAL_FORWARD_PRE - [0:0]
|
||||
:LOCAL_INPUT - [0:0]
|
||||
:LOCAL_INPUT_PRE - [0:0]
|
||||
:fail2ban-ssh - [0:0]
|
||||
-A INPUT -p tcp -m multiport --dports 22 -j fail2ban-ssh
|
||||
-A INPUT -i lo -m comment --comment "012 accept loopback" -j ACCEPT
|
||||
-A INPUT -p tcp -m multiport --dports 22 -m comment --comment "020 ssh" -j ACCEPT
|
||||
-A OUTPUT -d 1.2.1.2 -j DROP
|
||||
-A fail2ban-ssh -j RETURN
|
||||
COMMIT
|
||||
# Completed on Sun Jan 5 19:30:21 2014
|
||||
EOS
|
||||
)
|
||||
end
|
||||
|
||||
it 'should generate iptables resources' do
|
||||
resource = Puppet::Type::Firewallchain.new(:name => 'INPUT:filter:IPv4', :purge => true)
|
||||
|
||||
expect(resource.generate.size).to eq(3)
|
||||
end
|
||||
|
||||
it 'should not generate ignored iptables rules' do
|
||||
resource = Puppet::Type::Firewallchain.new(:name => 'INPUT:filter:IPv4', :purge => true, :ignore => ['-j fail2ban-ssh'])
|
||||
|
||||
expect(resource.generate.size).to eq(2)
|
||||
end
|
||||
|
||||
it 'should not generate iptables resources when not enabled' do
|
||||
resource = Puppet::Type::Firewallchain.new(:name => 'INPUT:filter:IPv4')
|
||||
|
||||
expect(resource.generate.size).to eq(0)
|
||||
end
|
||||
end
|
||||
end
|
197
modules/firewall/spec/unit/puppet/util/firewall_spec.rb
Normal file
197
modules/firewall/spec/unit/puppet/util/firewall_spec.rb
Normal file
|
@ -0,0 +1,197 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe 'Puppet::Util::Firewall' do
|
||||
let(:resource) {
|
||||
type = Puppet::Type.type(:firewall)
|
||||
provider = double 'provider'
|
||||
allow(provider).to receive(:name).and_return(:iptables)
|
||||
allow(Puppet::Type::Firewall).to receive(:defaultprovider).and_return(provider)
|
||||
type.new({:name => '000 test foo'})
|
||||
}
|
||||
|
||||
before(:each) { resource }
|
||||
|
||||
describe '#host_to_ip' do
|
||||
subject { resource }
|
||||
specify {
|
||||
expect(Resolv).to receive(:getaddress).with('puppetlabs.com').and_return('96.126.112.51')
|
||||
subject.host_to_ip('puppetlabs.com').should == '96.126.112.51/32'
|
||||
}
|
||||
specify { subject.host_to_ip('96.126.112.51').should == '96.126.112.51/32' }
|
||||
specify { subject.host_to_ip('96.126.112.51/32').should == '96.126.112.51/32' }
|
||||
specify { subject.host_to_ip('2001:db8:85a3:0:0:8a2e:370:7334').should == '2001:db8:85a3::8a2e:370:7334/128' }
|
||||
specify { subject.host_to_ip('2001:db8:1234::/48').should == '2001:db8:1234::/48' }
|
||||
specify { subject.host_to_ip('0.0.0.0/0').should == nil }
|
||||
specify { subject.host_to_ip('::/0').should == nil }
|
||||
end
|
||||
|
||||
describe '#host_to_mask' do
|
||||
subject { resource }
|
||||
specify {
|
||||
expect(Resolv).to receive(:getaddress).at_least(:once).with('puppetlabs.com').and_return('96.126.112.51')
|
||||
subject.host_to_mask('puppetlabs.com').should == '96.126.112.51/32'
|
||||
subject.host_to_mask('!puppetlabs.com').should == '! 96.126.112.51/32'
|
||||
}
|
||||
specify { subject.host_to_mask('96.126.112.51').should == '96.126.112.51/32' }
|
||||
specify { subject.host_to_mask('!96.126.112.51').should == '! 96.126.112.51/32' }
|
||||
specify { subject.host_to_mask('96.126.112.51/32').should == '96.126.112.51/32' }
|
||||
specify { subject.host_to_mask('! 96.126.112.51/32').should == '! 96.126.112.51/32' }
|
||||
specify { subject.host_to_mask('2001:db8:85a3:0:0:8a2e:370:7334').should == '2001:db8:85a3::8a2e:370:7334/128' }
|
||||
specify { subject.host_to_mask('!2001:db8:85a3:0:0:8a2e:370:7334').should == '! 2001:db8:85a3::8a2e:370:7334/128' }
|
||||
specify { subject.host_to_mask('2001:db8:1234::/48').should == '2001:db8:1234::/48' }
|
||||
specify { subject.host_to_mask('! 2001:db8:1234::/48').should == '! 2001:db8:1234::/48' }
|
||||
specify { subject.host_to_mask('0.0.0.0/0').should == nil }
|
||||
specify { subject.host_to_mask('!0.0.0.0/0').should == nil }
|
||||
specify { subject.host_to_mask('::/0').should == nil }
|
||||
specify { subject.host_to_mask('! ::/0').should == nil }
|
||||
end
|
||||
|
||||
describe '#icmp_name_to_number' do
|
||||
describe 'proto unsupported' do
|
||||
subject { resource }
|
||||
|
||||
%w{inet5 inet8 foo}.each do |proto|
|
||||
it "should reject invalid proto #{proto}" do
|
||||
expect { subject.icmp_name_to_number('echo-reply', proto) }.
|
||||
to raise_error(ArgumentError, "unsupported protocol family '#{proto}'")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'proto IPv4' do
|
||||
proto = 'inet'
|
||||
subject { resource }
|
||||
specify { subject.icmp_name_to_number('echo-reply', proto).should == '0' }
|
||||
specify { subject.icmp_name_to_number('destination-unreachable', proto).should == '3' }
|
||||
specify { subject.icmp_name_to_number('source-quench', proto).should == '4' }
|
||||
specify { subject.icmp_name_to_number('redirect', proto).should == '6' }
|
||||
specify { subject.icmp_name_to_number('echo-request', proto).should == '8' }
|
||||
specify { subject.icmp_name_to_number('router-advertisement', proto).should == '9' }
|
||||
specify { subject.icmp_name_to_number('router-solicitation', proto).should == '10' }
|
||||
specify { subject.icmp_name_to_number('time-exceeded', proto).should == '11' }
|
||||
specify { subject.icmp_name_to_number('parameter-problem', proto).should == '12' }
|
||||
specify { subject.icmp_name_to_number('timestamp-request', proto).should == '13' }
|
||||
specify { subject.icmp_name_to_number('timestamp-reply', proto).should == '14' }
|
||||
specify { subject.icmp_name_to_number('address-mask-request', proto).should == '17' }
|
||||
specify { subject.icmp_name_to_number('address-mask-reply', proto).should == '18' }
|
||||
end
|
||||
|
||||
describe 'proto IPv6' do
|
||||
proto = 'inet6'
|
||||
subject { resource }
|
||||
specify { subject.icmp_name_to_number('destination-unreachable', proto).should == '1' }
|
||||
specify { subject.icmp_name_to_number('time-exceeded', proto).should == '3' }
|
||||
specify { subject.icmp_name_to_number('parameter-problem', proto).should == '4' }
|
||||
specify { subject.icmp_name_to_number('echo-request', proto).should == '128' }
|
||||
specify { subject.icmp_name_to_number('echo-reply', proto).should == '129' }
|
||||
specify { subject.icmp_name_to_number('router-solicitation', proto).should == '133' }
|
||||
specify { subject.icmp_name_to_number('router-advertisement', proto).should == '134' }
|
||||
specify { subject.icmp_name_to_number('redirect', proto).should == '137' }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#string_to_port' do
|
||||
subject { resource }
|
||||
specify { subject.string_to_port('80','tcp').should == '80' }
|
||||
specify { subject.string_to_port(80,'tcp').should == '80' }
|
||||
specify { subject.string_to_port('http','tcp').should == '80' }
|
||||
specify { subject.string_to_port('domain','udp').should == '53' }
|
||||
end
|
||||
|
||||
describe '#to_hex32' do
|
||||
subject { resource }
|
||||
specify { subject.to_hex32('0').should == '0x0' }
|
||||
specify { subject.to_hex32('0x32').should == '0x32' }
|
||||
specify { subject.to_hex32('42').should == '0x2a' }
|
||||
specify { subject.to_hex32('4294967295').should == '0xffffffff' }
|
||||
specify { subject.to_hex32('4294967296').should == nil }
|
||||
specify { subject.to_hex32('-1').should == nil }
|
||||
specify { subject.to_hex32('bananas').should == nil }
|
||||
end
|
||||
|
||||
describe '#persist_iptables' do
|
||||
before { Facter.clear }
|
||||
subject { resource }
|
||||
|
||||
describe 'when proto is IPv4' do
|
||||
let(:proto) { 'IPv4' }
|
||||
|
||||
it 'should exec /sbin/service if running RHEL 6 or earlier' do
|
||||
allow(Facter.fact(:osfamily)).to receive(:value).and_return('RedHat')
|
||||
allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('RedHat')
|
||||
allow(Facter.fact(:operatingsystemrelease)).to receive(:value).and_return('6')
|
||||
|
||||
expect(subject).to receive(:execute).with(%w{/sbin/service iptables save})
|
||||
subject.persist_iptables(proto)
|
||||
end
|
||||
|
||||
it 'should exec for systemd if running RHEL 7 or greater' do
|
||||
allow(Facter.fact(:osfamily)).to receive(:value).and_return('RedHat')
|
||||
allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('RedHat')
|
||||
allow(Facter.fact(:operatingsystemrelease)).to receive(:value).and_return('7')
|
||||
|
||||
expect(subject).to receive(:execute).with(%w{/usr/libexec/iptables/iptables.init save})
|
||||
subject.persist_iptables(proto)
|
||||
end
|
||||
|
||||
it 'should exec for systemd if running Fedora 15 or greater' do
|
||||
allow(Facter.fact(:osfamily)).to receive(:value).and_return('RedHat')
|
||||
allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('Fedora')
|
||||
allow(Facter.fact(:operatingsystemrelease)).to receive(:value).and_return('15')
|
||||
|
||||
expect(subject).to receive(:execute).with(%w{/usr/libexec/iptables/iptables.init save})
|
||||
subject.persist_iptables(proto)
|
||||
end
|
||||
|
||||
it 'should exec for CentOS identified from operatingsystem' do
|
||||
allow(Facter.fact(:osfamily)).to receive(:value).and_return(nil)
|
||||
allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('CentOS')
|
||||
expect(subject).to receive(:execute).with(%w{/sbin/service iptables save})
|
||||
subject.persist_iptables(proto)
|
||||
end
|
||||
|
||||
it 'should exec for Archlinux identified from osfamily' do
|
||||
allow(Facter.fact(:osfamily)).to receive(:value).and_return('Archlinux')
|
||||
expect(subject).to receive(:execute).with(['/bin/sh', '-c', '/usr/sbin/iptables-save > /etc/iptables/iptables.rules'])
|
||||
subject.persist_iptables(proto)
|
||||
end
|
||||
|
||||
it 'should raise a warning when exec fails' do
|
||||
allow(Facter.fact(:osfamily)).to receive(:value).and_return('RedHat')
|
||||
allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('RedHat')
|
||||
allow(Facter.fact(:operatingsystemrelease)).to receive(:value).and_return('6')
|
||||
|
||||
expect(subject).to receive(:execute).with(%w{/sbin/service iptables save}).
|
||||
and_raise(Puppet::ExecutionFailure, 'some error')
|
||||
expect(subject).to receive(:warning).with('Unable to persist firewall rules: some error')
|
||||
subject.persist_iptables(proto)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when proto is IPv6' do
|
||||
let(:proto) { 'IPv6' }
|
||||
|
||||
it 'should exec for newer Ubuntu' do
|
||||
allow(Facter.fact(:osfamily)).to receive(:value).and_return(nil)
|
||||
allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('Ubuntu')
|
||||
allow(Facter.fact(:iptables_persistent_version)).to receive(:value).and_return('0.5.3ubuntu2')
|
||||
expect(subject).to receive(:execute).with(%w{/usr/sbin/service iptables-persistent save})
|
||||
subject.persist_iptables(proto)
|
||||
end
|
||||
|
||||
it 'should not exec for older Ubuntu which does not support IPv6' do
|
||||
allow(Facter.fact(:osfamily)).to receive(:value).and_return(nil)
|
||||
allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('Ubuntu')
|
||||
allow(Facter.fact(:iptables_persistent_version)).to receive(:value).and_return('0.0.20090701')
|
||||
expect(subject).to receive(:execute).never
|
||||
subject.persist_iptables(proto)
|
||||
end
|
||||
|
||||
it 'should not exec for Suse which is not supported' do
|
||||
allow(Facter.fact(:osfamily)).to receive(:value).and_return('Suse')
|
||||
expect(subject).to receive(:execute).never
|
||||
subject.persist_iptables(proto)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
67
modules/firewall/spec/unit/puppet/util/ipcidr_spec.rb
Normal file
67
modules/firewall/spec/unit/puppet/util/ipcidr_spec.rb
Normal file
|
@ -0,0 +1,67 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe 'Puppet::Util::IPCidr' do
|
||||
describe 'ipv4 address' do
|
||||
before { @ipaddr = Puppet::Util::IPCidr.new('96.126.112.51') }
|
||||
subject { @ipaddr }
|
||||
specify { subject.cidr.should == '96.126.112.51/32' }
|
||||
specify { subject.prefixlen.should == 32 }
|
||||
specify { subject.netmask.should == '255.255.255.255' }
|
||||
end
|
||||
|
||||
describe 'single ipv4 address with cidr' do
|
||||
before { @ipcidr = Puppet::Util::IPCidr.new('96.126.112.51/32') }
|
||||
subject { @ipcidr }
|
||||
specify { subject.cidr.should == '96.126.112.51/32' }
|
||||
specify { subject.prefixlen.should == 32 }
|
||||
specify { subject.netmask.should == '255.255.255.255' }
|
||||
end
|
||||
|
||||
describe 'ipv4 address range with cidr' do
|
||||
before { @ipcidr = Puppet::Util::IPCidr.new('96.126.112.0/24') }
|
||||
subject { @ipcidr }
|
||||
specify { subject.cidr.should == '96.126.112.0/24' }
|
||||
specify { subject.prefixlen.should == 24 }
|
||||
specify { subject.netmask.should == '255.255.255.0' }
|
||||
end
|
||||
|
||||
describe 'ipv4 open range with cidr' do
|
||||
before { @ipcidr = Puppet::Util::IPCidr.new('0.0.0.0/0') }
|
||||
subject { @ipcidr }
|
||||
specify { subject.cidr.should == '0.0.0.0/0' }
|
||||
specify { subject.prefixlen.should == 0 }
|
||||
specify { subject.netmask.should == '0.0.0.0' }
|
||||
end
|
||||
|
||||
describe 'ipv6 address' do
|
||||
before { @ipaddr = Puppet::Util::IPCidr.new('2001:db8:85a3:0:0:8a2e:370:7334') }
|
||||
subject { @ipaddr }
|
||||
specify { subject.cidr.should == '2001:db8:85a3::8a2e:370:7334/128' }
|
||||
specify { subject.prefixlen.should == 128 }
|
||||
specify { subject.netmask.should == 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff' }
|
||||
end
|
||||
|
||||
describe 'single ipv6 addr with cidr' do
|
||||
before { @ipaddr = Puppet::Util::IPCidr.new('2001:db8:85a3:0:0:8a2e:370:7334/128') }
|
||||
subject { @ipaddr }
|
||||
specify { subject.cidr.should == '2001:db8:85a3::8a2e:370:7334/128' }
|
||||
specify { subject.prefixlen.should == 128 }
|
||||
specify { subject.netmask.should == 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff' }
|
||||
end
|
||||
|
||||
describe 'ipv6 addr range with cidr' do
|
||||
before { @ipaddr = Puppet::Util::IPCidr.new('2001:db8:1234::/48') }
|
||||
subject { @ipaddr }
|
||||
specify { subject.cidr.should == '2001:db8:1234::/48' }
|
||||
specify { subject.prefixlen.should == 48 }
|
||||
specify { subject.netmask.should == 'ffff:ffff:ffff:0000:0000:0000:0000:0000' }
|
||||
end
|
||||
|
||||
describe 'ipv6 open range with cidr' do
|
||||
before { @ipaddr = Puppet::Util::IPCidr.new('::/0') }
|
||||
subject { @ipaddr }
|
||||
specify { subject.cidr.should == '::/0' }
|
||||
specify { subject.prefixlen.should == 0 }
|
||||
specify { subject.netmask.should == '0000:0000:0000:0000:0000:0000:0000:0000' }
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue