128 changes: 0 additions & 128 deletions examples/iptables/test.pp

This file was deleted.

4 changes: 2 additions & 2 deletions lib/puppet/provider/firewall/ip6tables.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
has_feature :pkttype

optional_commands({
:ip6tables => '/sbin/ip6tables',
:ip6tables_save => '/sbin/ip6tables-save',
:ip6tables => 'ip6tables',
:ip6tables_save => 'ip6tables-save',
})

def self.iptables(*args)
Expand Down
31 changes: 21 additions & 10 deletions lib/puppet/provider/firewall/iptables.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@
has_feature :mark
has_feature :tcp_flags
has_feature :pkttype
has_feature :isfragment
has_feature :socket

optional_commands({
:iptables => '/sbin/iptables',
:iptables_save => '/sbin/iptables-save',
:iptables => 'iptables',
:iptables_save => 'iptables-save',
})

defaultfor :kernel => :linux
Expand Down Expand Up @@ -65,7 +66,8 @@
:toports => "--to-ports",
:tosource => "--to-source",
:uid => "-m owner --uid-owner",
:pkttype => "-m pkttype --pkt-type"
:pkttype => "-m pkttype --pkt-type",
:isfragment => "-f",
}

# Create property methods dynamically
Expand All @@ -84,7 +86,7 @@
# changes between puppet runs, the changed rules will be re-applied again.
# This order can be determined by going through iptables source code or just tweaking and trying manually
@resource_list = [:table, :source, :destination, :iniface, :outiface,
:proto, :tcp_flags, :gid, :uid, :sport, :dport, :port, :socket, :pkttype, :name, :state, :icmp, :limit, :burst,
:proto, :isfragment, :tcp_flags, :gid, :uid, :sport, :dport, :port, :socket, :pkttype, :name, :state, :icmp, :limit, :burst,
:jump, :todest, :tosource, :toports, :log_level, :log_prefix, :reject, :set_mark]

def insert
Expand Down Expand Up @@ -146,7 +148,7 @@ def self.rule_to_hash(line, table, counter)

# These are known booleans that do not take a value, but we want to munge
# to true if they exist.
known_booleans = [:socket]
known_booleans = [:socket, :isfragment]

####################
# PRE-PARSE CLUDGING
Expand All @@ -158,7 +160,14 @@ def self.rule_to_hash(line, table, counter)

# Trick the system for booleans
known_booleans.each do |bool|
values = values.sub(/#{@resource_map[bool]}/, '-m socket true')
if bool == :socket then
values = values.sub(/#{@resource_map[bool]}/, '-m socket true')
end
if bool == :isfragment then
# only replace those -f that are not followed by an l to
# distinguish between -f and the '-f' inside of --tcp-flags.
values = values.sub(/-f(?=[^l])/, '-f true')
end
end

############
Expand Down Expand Up @@ -199,9 +208,7 @@ def self.rule_to_hash(line, table, counter)
# Convert booleans removing the previous cludge we did
known_booleans.each do |bool|
if hash[bool] != nil then
if hash[bool] == "true" then
hash[bool] = true
else
unless hash[bool] == "true" then
raise "Parser error: #{bool} was meant to be a boolean but received value: #{hash[bool]}."
end
end
Expand All @@ -225,7 +232,8 @@ def self.rule_to_hash(line, table, counter)
# Puppet-firewall requires that all rules have comments (resource names) and will fail if
# a rule in iptables does not have a comment. We get around this by appending a high level
if ! hash[:name]
hash[:name] = "9999 #{Digest::MD5.hexdigest(line)}"
num = 9000 + counter
hash[:name] = "#{num} #{Digest::MD5.hexdigest(line)}"
end

# Iptables defaults to log_level '4', so it is omitted from the output of iptables-save.
Expand Down Expand Up @@ -312,6 +320,9 @@ def general_args
if res == :socket then
resource_value = nil
end
if res == :isfragment then
resource_value = nil
end
elsif res == :jump and resource[:action] then
# In this case, we are substituting jump for action
resource_value = resource[:action].to_s.upcase
Expand Down
12 changes: 6 additions & 6 deletions lib/puppet/provider/firewallchain/iptables_chain.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
has_feature :policy

optional_commands({
:iptables => '/sbin/iptables',
:iptables_save => '/sbin/iptables-save',
:ip6tables => '/sbin/ip6tables',
:ip6tables_save => '/sbin/ip6tables-save',
:ebtables => '/sbin/ebtables',
:ebtables_save => '/sbin/ebtables-save',
:iptables => 'iptables',
:iptables_save => 'iptables-save',
:ip6tables => 'ip6tables',
:ip6tables_save => 'ip6tables-save',
:ebtables => 'ebtables',
:ebtables_save => 'ebtables-save',
})

defaultfor :kernel => :linux
Expand Down
21 changes: 19 additions & 2 deletions lib/puppet/type/firewall.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
feature :tcp_flags, "The ability to match on particular TCP flag settings"
feature :pkttype, "Match a packet type"
feature :socket, "Match open sockets"
feature :isfragment, "Match fragments"

# provider specific features
feature :iptables, "The provider provides iptables features."
Expand Down Expand Up @@ -104,7 +105,11 @@
EOS

munge do |value|
@resource.host_to_ip(value)
begin
@resource.host_to_ip(value)
rescue Exception => e
self.fail("host_to_ip failed for #{value}, exception #{e}")
end
end
end

Expand All @@ -118,7 +123,11 @@
EOS

munge do |value|
@resource.host_to_ip(value)
begin
@resource.host_to_ip(value)
rescue Exception => e
self.fail("host_to_ip failed for #{value}, exception #{e}")
end
end
end

Expand Down Expand Up @@ -543,6 +552,14 @@ def should_to_s(value)
newvalues(:unicast, :broadcast, :multicast)
end

newproperty(:isfragment, :required_features => :isfragment) do
desc <<-EOS
Set to true to match tcp fragments (requires type to be set to tcp)
EOS

newvalues(:true, :false)
end

newproperty(:socket, :required_features => :socket) do
desc <<-EOS
If true, matches if an open socket can be found by doing a coket lookup
Expand Down
19 changes: 19 additions & 0 deletions lib/puppet/util/firewall.rb
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,11 @@ def persist_iptables(proto)
end
end

# Fedora 15 and newer use systemd for to persist iptable rules
if os_key == 'RedHat' && Facter.value(:operatingsystem) == 'Fedora' && Facter.value(:operatingsystemrelease).to_i >= 15
os_key = 'Fedora'
end

cmd = case os_key.to_sym
when :RedHat
case proto.to_sym
Expand All @@ -160,6 +165,13 @@ def persist_iptables(proto)
when :IPv6
%w{/sbin/service ip6tables save}
end
when :Fedora
case proto.to_sym
when :IPv4
%w{/usr/libexec/iptables.init save}
when :IPv6
%w{/usr/libexec/ip6tables.init save}
end
when :Debian
case proto.to_sym
when :IPv4, :IPv6
Expand All @@ -170,6 +182,13 @@ def persist_iptables(proto)
when :IPv4
["/bin/sh", "-c", "/sbin/iptables-save > /etc/iptables/rules"]
end
when :Archlinux
case proto.to_sym
when :IPv4
["/bin/sh", "-c", "/usr/sbin/iptables-save > /etc/iptables/iptables.rules"]
when :IPv6
["/bin/sh", "-c", "/usr/sbin/ip6tables-save > /etc/iptables/ip6tables.rules"]
end
end

# Catch unsupported OSs from the case statement above.
Expand Down
17 changes: 15 additions & 2 deletions manifests/init.pp
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,23 @@
# Manages the installation of packages for operating systems that are
# currently supported by the firewall type.
#
class firewall {
class firewall (
$ensure = running
) {
case $ensure {
/^(running|stopped)$/: {
# Do nothing.
}
default: {
fail("${title}: Ensure value '${ensure}' is not supported")
}
}

case $::kernel {
'Linux': {
class { "${title}::linux": }
class { "${title}::linux":
ensure => $ensure,
}
}
default: {
fail("${title}: Kernel '${::kernel}' is not currently supported")
Expand Down
20 changes: 19 additions & 1 deletion manifests/linux.pp
Original file line number Diff line number Diff line change
@@ -1,16 +1,34 @@
class firewall::linux {
class firewall::linux (
$ensure = running
) {
$enable = $ensure ? {
running => true,
stopped => false,
}

package { 'iptables':
ensure => present,
}

case $::operatingsystem {
'RedHat', 'CentOS', 'Fedora': {
class { "${title}::redhat":
ensure => $ensure,
enable => $enable,
require => Package['iptables'],
}
}
'Debian', 'Ubuntu': {
class { "${title}::debian":
ensure => $ensure,
enable => $enable,
require => Package['iptables'],
}
}
'Archlinux': {
class { "${title}::archlinux":
ensure => $ensure,
enable => $enable,
require => Package['iptables'],
}
}
Expand Down
24 changes: 24 additions & 0 deletions manifests/linux/archlinux.pp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
class firewall::linux::archlinux (
$ensure = 'running',
$enable = true
) {
service { 'iptables':
ensure => $ensure,
enable => $enable,
}

service { 'ip6tables':
ensure => $ensure,
enable => $enable,
}

file { '/etc/iptables/iptables.rules':
ensure => present,
before => Service['iptables'],
}

file { '/etc/iptables/ip6tables.rules':
ensure => present,
before => Service['ip6tables'],
}
}
28 changes: 21 additions & 7 deletions manifests/linux/debian.pp
Original file line number Diff line number Diff line change
@@ -1,13 +1,27 @@
class firewall::linux::debian {
class firewall::linux::debian (
$ensure = running,
$enable = true
) {
package { 'iptables-persistent':
ensure => present,
}

# This isn't a real service/daemon. The start action loads rules, so just
# needs to be called on system boot.
service { 'iptables-persistent':
ensure => undef,
enable => true,
require => Package['iptables-persistent'],
if($operatingsystemrelease =~ /^6\./ and $enable == true) {
# This fixes a bug in the iptables-persistent LSB headers in 6.x, without it
# we lose idempotency
exec { 'iptables-persistent-enable':
logoutput => on_failure,
command => '/usr/sbin/update-rc.d iptables-persistent enable',
unless => '/usr/bin/test -f /etc/rcS.d/S*iptables-persistent',
require => Package['iptables-persistent'],
}
} else {
# This isn't a real service/daemon. The start action loads rules, so just
# needs to be called on system boot.
service { 'iptables-persistent':
ensure => undef,
enable => $enable,
require => Package['iptables-persistent'],
}
}
}
9 changes: 6 additions & 3 deletions manifests/linux/redhat.pp
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
class firewall::linux::redhat {
class firewall::linux::redhat (
$ensure = running,
$enable = true
) {
service { 'iptables':
ensure => running,
enable => true,
ensure => $ensure,
enable => $enable,
}
}
8 changes: 0 additions & 8 deletions spec/classes/firewall_linux_redhat_spec.rb

This file was deleted.

8 changes: 0 additions & 8 deletions spec/classes/firewall_spec.rb

This file was deleted.

18 changes: 18 additions & 0 deletions spec/fixtures/iptables/conversion_hash.rb
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,14 @@
:socket => true,
},
},
'isfragment_option' => {
:line => '-A INPUT -f -j ACCEPT',
:table => 'filter',
:params => {
:action => 'accept',
:isfragment => true,
},
},
'single_tcp_sport' => {
:line => '-A OUTPUT -s 10.94.100.46/32 -p tcp -m tcp --sport 20443 -j ACCEPT',
:table => 'mangle',
Expand Down Expand Up @@ -706,4 +714,14 @@
},
:args => ['-t', :mangle, '-p', :tcp, '-m', 'socket', '-m', 'comment', '--comment', '050 socket option', '-j', 'ACCEPT'],
},
'isfragment_option' => {
:params => {
:name => '050 isfragment option',
:table => 'filter',
:proto => :all,
:action => 'accept',
:isfragment => true,
},
:args => ['-t', :filter, '-p', :all, '-f', '-m', 'comment', '--comment', '050 isfragment option', '-j', 'ACCEPT'],
},
}
1 change: 1 addition & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
fixture_path = File.expand_path(File.join(__FILE__, '..', 'fixtures'))

RSpec.configure do |config|
config.tty = true
config.mock_with :mocha
config.module_path = File.join(fixture_path, 'modules')
config.manifest_dir = File.join(fixture_path, 'manifests')
Expand Down
49 changes: 49 additions & 0 deletions spec/spec_helper_system.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# This helper file is specific to the system tests for puppetlabs-firewall
# and should be included by all tests under spec/system
require 'rspec-system/spec_helper'
require 'rspec-system-puppet/helpers'

# Just some helpers specific to this module
module LocalHelpers
# This helper flushes all tables on the default machine.
#
# It checks that the flush command returns with no errors.
#
# @return [void]
# @todo Need to optionally do the newer tables
# @example
# it 'should flush tables' do
# iptables_flush_all_tables
# end
def iptables_flush_all_tables
['filter', 'nat', 'mangle', 'raw'].each do |t|
system_run("/sbin/iptables -t #{t} -F") do |r|
r[:exit_code].should == 0
r[:stderr].should == ''
end
end
end
end

RSpec.configure do |c|
# Project root for the firewall code
proj_root = File.expand_path(File.join(File.dirname(__FILE__), '..'))

# Enable colour in Jenkins
c.tty = true

# Import in our local helpers
c.include ::LocalHelpers

# This is where we 'setup' the nodes before running our tests
c.system_setup_block = proc do
# TODO: find a better way of importing this into this namespace
include RSpecSystemPuppet::Helpers

# Install puppet
puppet_install

# Copy this module into the module path of the test node
puppet_module_install(:source => proj_root, :module_name => 'firewall')
end
end
13 changes: 13 additions & 0 deletions spec/system/basic_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
require 'spec_helper_system'

# Here we put the more basic fundamental tests, ultra obvious stuff.
describe "basic tests:" do
it 'make sure we have copied the module across' do
# No point diagnosing any more if the module wasn't copied properly
system_run("ls /etc/puppet/modules/firewall") do |r|
r[:exit_code].should == 0
r[:stdout].should =~ /Modulefile/
r[:stderr].should == ''
end
end
end
73 changes: 73 additions & 0 deletions spec/system/class_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
require 'spec_helper_system'

describe "firewall class:" do
context 'no params:' do
let(:pp) do
pp = <<-EOS.gsub(/^\s{8}/,'')
class { 'firewall': }
EOS
end

it "should run without event" do
puppet_apply(pp) do |r|
r[:stderr].should == ''
r[:exit_code].should_not eq(1)
end
end

it "should be idempotent" do
puppet_apply(pp) do |r|
r[:stderr].should == ''
r[:exit_code].should == 0
end
end
end

context 'ensure => stopped:' do
let(:pp) do
pp = <<-EOS.gsub(/^\s{8}/,'')
class { 'firewall':
ensure => stopped,
}
EOS
end

it "should run without event" do
puppet_apply(pp) do |r|
r[:stderr].should == ''
r[:exit_code].should_not eq(1)
end
end

it "should be idempotent" do
puppet_apply(pp) do |r|
r[:stderr].should == ''
r[:exit_code].should == 0
end
end
end

context 'ensure => running:' do
let(:pp) do
pp = <<-EOS.gsub(/^\s{8}/,'')
class { 'firewall':
ensure => running,
}
EOS
end

it "should run without event" do
puppet_apply(pp) do |r|
r[:stderr].should == ''
r[:exit_code].should_not eq(1)
end
end

it "should be idempotent" do
puppet_apply(pp) do |r|
r[:stderr].should == ''
r[:exit_code].should == 0
end
end
end
end
48 changes: 48 additions & 0 deletions spec/system/params_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
require 'spec_helper_system'

describe "param based tests:" do
def pp(params)
pm = <<-EOS
firewall { '100 test':
EOS

params.each do |k,v|
pm += <<-EOS
#{k} => #{v},
EOS
end

pm += <<-EOS
}
EOS
pm
end

it 'test socket param' do
facts = system_node.facts

unless (facts['operatingsystem'] == 'CentOS') && \
facts['operatingsystemrelease'] =~ /^5\./ then

iptables_flush_all_tables

param = {
'table' => "'raw'",
'socket' => 'true',
'chain' => "'PREROUTING'",
}
ppm = pp(param)
puppet_apply(ppm) do |r|
r[:stderr].should == ''
r[:exit_code].should == 2
end

# check idempotency
puppet_apply(ppm) do |r|
r[:stderr].should == ''
r[:exit_code].should == 0
end
end
end

end
25 changes: 25 additions & 0 deletions spec/system/purge_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
require 'spec_helper_system'

describe "purge tests:" do
it 'make sure duplicate existing rules get purged' do
iptables_flush_all_tables

system_run('/sbin/iptables -A INPUT -s 1.2.1.2')
system_run('/sbin/iptables -A INPUT -s 1.2.1.2')
pp = <<-EOS
class { 'firewall': }
resources { 'firewall':
purge => true,
}
EOS
puppet_apply(pp) do |r|
r[:stderr].should == ''
r[:exit_code].should == 2
end

system_run('/sbin/iptables-save') do |r|
r[:stdout].should_not =~ /1\.2\.1\.2/
r[:stderr].should == ''
end
end
end
25 changes: 25 additions & 0 deletions spec/system/resource_cmd_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
require 'spec_helper_system'

# Here we want to test the the resource commands ability to work with different
# existing ruleset scenarios. This will give the parsing capabilities of the
# code a good work out.
describe 'puppet resource firewall command:' do
it 'make sure it returns no errors when executed on a clean machine' do
puppet_resource('firewall') do |r|
r[:exit_code].should == 0
# don't check stdout, some boxes come with rules, that is normal
r[:stderr].should == ''
end
end

it 'flush iptables and make sure it returns nothing afterwards' do
iptables_flush_all_tables

# No rules, means no output thanks. And no errors as well.
puppet_resource('firewall') do |r|
r[:exit_code].should == 0
r[:stderr].should == ''
r[:stdout].should == "\n"
end
end
end
65 changes: 65 additions & 0 deletions spec/system/stanard_usage_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
require 'spec_helper_system'

# Some tests for the standard recommended usage
describe "standard usage:" do
let(:pp) do
pp = <<-EOS
class my_fw::pre {
Firewall {
require => undef,
}
# Default firewall rules
firewall { '000 accept all icmp':
proto => 'icmp',
action => 'accept',
}->
firewall { '001 accept all to lo interface':
proto => 'all',
iniface => 'lo',
action => 'accept',
}->
firewall { '002 accept related established rules':
proto => 'all',
state => ['RELATED', 'ESTABLISHED'],
action => 'accept',
}
}
class my_fw::post {
firewall { '999 drop all':
proto => 'all',
action => 'drop',
before => undef,
}
}
resources { "firewall":
purge => true
}
Firewall {
before => Class['my_fw::post'],
require => Class['my_fw::pre'],
}
class { ['my_fw::pre', 'my_fw::post']: }
class { 'firewall': }
firewall { '500 open up port 22':
action => 'accept',
proto => 'tcp',
dport => 22,
}
EOS
end

it 'make sure it runs without error' do
puppet_apply(pp) do |r|
r[:stderr].should == ''
r[:exit_code].should_not eq(1)
end
end

it 'should be idempotent' do
puppet_apply(pp) do |r|
r[:stderr].should == ''
r[:exit_code].should == 0
end
end
end
32 changes: 32 additions & 0 deletions spec/unit/classes/firewall_linux_archlinux_spec.rb
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
require 'spec_helper'

describe 'firewall::linux::debian' do
describe 'firewall::linux::debian', :type => :class do
it { should contain_package('iptables-persistent').with(
:ensure => 'present'
)}
Expand All @@ -9,4 +9,11 @@
: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
22 changes: 22 additions & 0 deletions spec/unit/classes/firewall_linux_redhat_spec.rb
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
require 'spec_helper'

describe 'firewall::linux' do
describe 'firewall::linux', :type => :class do
let(:facts_default) {{ :kernel => 'Linux' }}
it { should contain_package('iptables').with_ensure('present') }

Expand Down
25 changes: 25 additions & 0 deletions spec/unit/classes/firewall_spec.rb
Original file line number Diff line number Diff line change
@@ -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 include_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 include_class('firewall::linux') }.to raise_error(Puppet::Error) }
end
end
14 changes: 7 additions & 7 deletions spec/unit/puppet/provider/iptables_chain_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,25 @@

it "should default to iptables provider if /sbin/(eb|ip|ip6)tables[-save] exists" do
# Stub lookup for /sbin/iptables & /sbin/iptables-save
exists.any_instance.stubs(:which).with("/sbin/ebtables").
exists.any_instance.stubs(:which).with("ebtables").
returns "/sbin/ebtables"
exists.any_instance.stubs(:which).with("/sbin/ebtables-save").
exists.any_instance.stubs(:which).with("ebtables-save").
returns "/sbin/ebtables-save"

exists.any_instance.stubs(:which).with("/sbin/iptables").
exists.any_instance.stubs(:which).with("iptables").
returns "/sbin/iptables"
exists.any_instance.stubs(:which).with("/sbin/iptables-save").
exists.any_instance.stubs(:which).with("iptables-save").
returns "/sbin/iptables-save"

exists.any_instance.stubs(:which).with("/sbin/ip6tables").
exists.any_instance.stubs(:which).with("ip6tables").
returns "/sbin/ip6tables"
exists.any_instance.stubs(:which).with("/sbin/ip6tables-save").
exists.any_instance.stubs(:which).with("ip6tables-save").
returns "/sbin/ip6tables-save"

# Every other command should return false so we don't pick up any
# other providers
exists.any_instance.stubs(:which).with() { |value|
value !~ /\/sbin\/(eb|ip|ip6)tables(-save)?$/
value !~ /(eb|ip|ip6)tables(-save)?$/
}.returns false

# Create a resource instance and make sure the provider is iptables
Expand Down
17 changes: 11 additions & 6 deletions spec/unit/puppet/provider/iptables_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@

it "should default to iptables provider if /sbin/iptables[-save] exists" do
# Stub lookup for /sbin/iptables & /sbin/iptables-save
exists.any_instance.stubs(:which).with("/sbin/iptables").
exists.any_instance.stubs(:which).with("iptables").
returns "/sbin/iptables"
exists.any_instance.stubs(:which).with("/sbin/iptables-save").
exists.any_instance.stubs(:which).with("iptables-save").
returns "/sbin/iptables-save"

# Every other command should return false so we don't pick up any
# other providers
exists.any_instance.stubs(:which).with() { |value|
! ["/sbin/iptables","/sbin/iptables-save"].include?(value)
! ["iptables","iptables-save"].include?(value)
}.returns false

# Create a resource instance and make sure the provider is iptables
Expand Down Expand Up @@ -51,7 +51,7 @@
Facter.fact(:iptables_version).stubs(:value).returns("1.4.2")

Puppet::Util::Execution.stubs(:execute).returns ""
Puppet::Util.stubs(:which).with("/sbin/iptables-save").
Puppet::Util.stubs(:which).with("iptables-save").
returns "/sbin/iptables-save"
end

Expand Down Expand Up @@ -87,7 +87,12 @@
# 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]
# booleans get cludged to string "true"
if param_value == true then
resource[param_name].should == "true"
else
resource[param_name].should == data[:params][param_name]
end
end
end
end
Expand Down Expand Up @@ -116,7 +121,7 @@
let(:instance) { provider.new(resource) }

it 'rule name contains a MD5 sum of the line' do
resource[:name].should == "9999 #{Digest::MD5.hexdigest(resource[:line])}"
resource[:name].should == "9000 #{Digest::MD5.hexdigest(resource[:line])}"
end
end

Expand Down
19 changes: 19 additions & 0 deletions spec/unit/puppet/util/firewall_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -97,19 +97,38 @@

it 'should exec for RedHat identified from osfamily' do
Facter.fact(:osfamily).stubs(:value).returns('RedHat')
Facter.fact(:operatingsystem).stubs(:value).returns('RedHat')

subject.expects(:execute).with(%w{/sbin/service iptables save})
subject.persist_iptables(proto)
end

it 'should exec for systemd if running Fedora 15 or greater' do
Facter.fact(:osfamily).stubs(:value).returns('RedHat')
Facter.fact(:operatingsystem).stubs(:value).returns('Fedora')
Facter.fact(:operatingsystemrelease).stubs(:value).returns('15')

subject.expects(:execute).with(%w{/usr/libexec/iptables.init save})
subject.persist_iptables(proto)
end

it 'should exec for CentOS identified from operatingsystem' do
Facter.fact(:osfamily).stubs(:value).returns(nil)
Facter.fact(:operatingsystem).stubs(:value).returns('CentOS')
subject.expects(:execute).with(%w{/sbin/service iptables save})
subject.persist_iptables(proto)
end

it 'should exec for Archlinux identified from osfamily' do
Facter.fact(:osfamily).stubs(:value).returns('Archlinux')
subject.expects(: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
Facter.fact(:osfamily).stubs(:value).returns('RedHat')
Facter.fact(:operatingsystem).stubs(:value).returns('RedHat')

subject.expects(:execute).with(%w{/sbin/service iptables save}).
raises(Puppet::ExecutionFailure, 'some error')
subject.expects(:warning).with('Unable to persist firewall rules: some error')
Expand Down