]> review.fuel-infra Code Review - puppet-modules/puppetlabs-firewall.git/commitdiff
(#10162) Various fixes for firewallchain resource
authorKen Barber <ken@bob.sh>
Mon, 12 Mar 2012 04:16:33 +0000 (21:16 -0700)
committerKen Barber <ken@bob.sh>
Mon, 12 Mar 2012 07:42:03 +0000 (00:42 -0700)
* Convert commands to optional_commands to avoid iptables installation chicken
  & egg scenarios.
* Downcase tables to match the table names in xtables
* Force fully qualifying the name as <table>:<chain>:<protocol>, we can add
  meaningful defaults later.
* puppet resource <name> command wasn't working as expected, but stripping out
  some of the meaningful defaults I was able to get this to work.
* Reformat some of the code to avoid overrunning 80 chars where possible
* Remove trailing whitespace
* Add flush to provider so that resource modifications immediately update the
  resource in reports and when using puppet resource.
* Removed any commented out code
* Improved documentation
* Change policy so its undefined when not set, instead of being :empty
* Fix test mocking so they will run on a Mac

README.markdown
lib/puppet/provider/firewallchain/iptables_chain.rb
lib/puppet/type/firewallchain.rb
spec/unit/puppet/provider/iptables_chain_spec.rb
spec/unit/puppet/type/firewallchain_spec.rb

index a144deb606ffc2991ae3f6c579446fac6329e8ac..04c8865154e2779893681d1cbd5c83a315bc3d10 100644 (file)
@@ -4,14 +4,21 @@
 
 ### Overview
 
-This type provides the capability to manage firewall rules within 
-puppet.
+This module provides the resource 'firewall' which provides the capability to
+manage firewall rules within puppet.
 
 Current support includes:
 
 * iptables
 * ip6tables
 
+With the resource 'firewallchain' we also provide a mechanism to manage chains
+for:
+
+* iptables
+* ip6tables
+* ebtables
+
 ### Disclaimer
 
 Warning! While this software is written in the best interest of quality it has
@@ -93,6 +100,23 @@ Source NAT example (perfect for a virtualization host):
       table  => 'nat',
     }
 
+Creating a new rule that forwards to a chain, then adding a rule to this chain:
+
+    firewall { '100 forward to MY_CHAIN':
+      chain   => 'INPUT',
+      jump    => 'MY_CHAIN',
+      require => Firewallchain["filter:MY_CHAIN:IPv4"],
+    }
+    firewallchain { 'filter:MY_CHAIN:IPv4':
+      ensure  => present,
+    }
+    firewall { '100 my rule':
+      chain   => 'MY_CHAIN',
+      action  => 'accept',
+      proto   => 'tcp',
+      dport   => 5000,
+    }
+
 You can make firewall rules persistent with the following iptables example:
 
     exec { "persist-firewall":
@@ -105,6 +129,9 @@ You can make firewall rules persistent with the following iptables example:
     Firewall {
       notify => Exec["persist-firewall"]
     }
+    Firewallchain {
+      notify => Exec["persist-firewall"]
+    }
 
 If you wish to ensure any reject rules are executed last, try using stages.
 The following example shows the creation of a class which is where your
@@ -156,6 +183,7 @@ Currently we support:
 
 * iptables
 * ip6tables
+* ebtables (chains only)
 
 But plans are to support lots of other firewall implementations:
 
index 4198291f44efe9f8eb106e699bddd0807ace1e24..845792a5ad9b344a3e324fcb3ffbcb0eebee8395 100644 (file)
@@ -1,31 +1,42 @@
-
 Puppet::Type.type(:firewallchain).provide :iptables_chain do
   @doc = "Iptables chain provider"
 
   has_feature :iptables_chain
   has_feature :policy
 
-  commands :iptables => '/sbin/iptables'
-  commands :iptables_save => '/sbin/iptables-save'
-
-  commands :ip6tables => '/sbin/ip6tables'
-  commands :ip6tables_save => '/sbin/ip6tables-save'
-
-  optional_commands( { :ebtables => '/sbin/ebtables',
-                       :ebtables_save => '/sbin/ebtables-save'
-  } )
+  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',
+  })
 
   defaultfor :kernel => :linux
 
   # chain name is greedy so we anchor from the end.
   # [\d+:\d+] doesn't exist on ebtables
-  Mapping = { :IPv4     => { :tables => method( :iptables ),  :save => method( :iptables_save),   :re => /^:(.+)\s(\S+)\s\[\d+:\d+\]$/  },
-              :IPv6     => { :tables => method( :ip6tables ), :save => method( :ip6tables_save ), :re => /^:(.+)\s(\S+)\s\[\d+:\d+\]$/   },
-              :ethernet => { :tables => method( :ebtables ),  :save => method( :ebtables_save ),  :re => /^:(.+)\s(\S+)$/   }
-             }
+  Mapping = {
+    :IPv4 => {
+      :tables => method(:iptables),
+      :save   => method(:iptables_save),
+      :re     => /^:(.+)\s(\S+)\s\[\d+:\d+\]$/,
+    },
+    :IPv6 => {
+      :tables => method(:ip6tables),
+      :save   => method(:ip6tables_save),
+      :re     => /^:(.+)\s(\S+)\s\[\d+:\d+\]$/,
+    },
+    :ethernet => {
+      :tables => method(:ebtables),
+      :save   => method(:ebtables_save),
+      :re     => /^:(.+)\s(\S+)$/,
+    }
+  }
   InternalChains = /^(PREROUTING|POSTROUTING|BROUTING|INPUT|FORWARD|OUTPUT)$/
-  Tables = 'NAT|MANGLE|FILTER|RAW|RAWPOST|BROUTE|'
-  Nameformat = /^(#{Tables}):(.+):(IP(v[46])?|ethernet|)$/
+  Tables = 'nat|mangle|filter|raw|rawpost|broute'
+  Nameformat = /^(#{Tables}):(.+):(IP(v[46])?|ethernet)$/
 
   def create
     # can't create internal chains
@@ -38,8 +49,8 @@ Puppet::Type.type(:firewallchain).provide :iptables_chain do
       else
         debug "Inserting chain #{chain} on table #{table} (#{protocol}) using #{t}"
         t.call ['-t',table,'-N',chain]
-        if @resource[:policy] != :empty
-          t.call ['-t',table,'-P',chain,@resource[:policy].to_s.upcase] 
+        unless @resource[:policy].nil?
+          t.call ['-t',table,'-P',chain,@resource[:policy].to_s.upcase]
         end
       end
     end
@@ -52,19 +63,18 @@ Puppet::Type.type(:firewallchain).provide :iptables_chain do
     end
     allvalidchains do |t, table, chain|
       debug "Deleting chain #{chain} on table #{table}"
-      t.call ['-t',table,'-X',chain] 
+      t.call ['-t',table,'-X',chain]
     end
   end
 
   def exists?
-    # we want puppet to call create on 1/2 completed rules (i.e. :ensure => :IPv4/6)
     properties[:ensure] == :present
   end
 
   def policy=(value)
     return if value == :empty
     allvalidchains do |t, table, chain|
-      p =  ['-t',table,'-P',chain,value.to_s.upcase]
+      p = ['-t',table,'-P',chain,value.to_s.upcase]
       debug "[set policy] #{t} #{p}"
       t.call p
     end
@@ -84,12 +94,17 @@ Puppet::Type.type(:firewallchain).provide :iptables_chain do
     end
   end
 
+  def flush
+    debug("[flush]")
+    # Clear the property hash so we re-initialize with updated values
+    @property_hash.clear
+  end
+
   # Look up the current status. This allows us to conventiently look up
   # existing status with properties[:foo].
   def properties
     if @property_hash.empty?
       @property_hash = query || {:ensure => :absent}
-      #@property_hash[:ensure] = :absent if @property_hash.empty?
     end
     @property_hash.dup
   end
@@ -109,61 +124,41 @@ Puppet::Type.type(:firewallchain).provide :iptables_chain do
     debug "[instances]"
     table = nil
     chains = []
-    hash = {}
 
     Mapping.each { |p, c|
       begin
-        c[:save].call.split("\n").each do |line|
+        c[:save].call.each_line do |line|
           if line =~ c[:re] then
-            name = (table == 'filter' ? '' : table.upcase) + ':' + $1
-            policy = $2 == '-' ? :empty : $2.downcase.to_sym
-            if ( p == :IPv4 or p == :IPv6 ) && table != 'nat'
-              if hash[name]
-                # duplicate so create a {table}:{chain}:IP instance
-                ippolicy = hash[name][:policy] == policy ? policy : :inconsistent
-                hash.delete(name)
-                chains << new({:name => name + ':', :policy => ippolicy, :ensure => :present })
-                debug "[dup] '#{name}:' #{ippolicy}"
-              else
-                hash[name] = { :policy => policy, :protocol => p }
-              end
-            end
-            name += ':' + p.to_s
-            chains << new({:name => name, :policy => policy, :ensure => :present })
+            name = (table == 'filter' ? 'filter' : table) + ':' + $1 + ':' + p.to_s
+            policy = $2 == '-' ? nil : $2.downcase.to_sym
+
+            chains << new({
+              :name   => name,
+              :policy => policy,
+              :ensure => :present,
+            })
+
             debug "[instance] '#{name}' #{policy}"
           elsif line =~ /^\*(\S+)/
             table = $1
-          elsif line =~ /^($|-A|COMMIT|#)/
-            # other stuff we don't care about
           else
-            debug "unrecognised line: #{line}"
+            next
           end
         end
       rescue Puppet::Error
         # ignore command not found for ebtables or anything that doesn't exist
       end
     }
-    # put all the chain names that exist in one IP stack into a 1/2 completed (:ensure) state
-    # The create method will check this and complete only what's required
-    hash.each { |key, value|
-      x = {:name => key + ':', :ensure => value[:protocol], :policy => :empty}
-      debug "halfstate #{x.inspect}"
-      chains << new(x)
-    }
+
     chains
   end
 
   def allvalidchains
     @resource[:name].match(Nameformat)
-    table = ($1=='') ? 'filter' : $1.downcase
+    table = $1
     chain = $2
     protocol = $3
-    if protocol == 'IP' || protocol == ''
-      yield Mapping[:IPv4][:tables],table,chain,:IPv4
-      yield Mapping[:IPv6][:tables],table,chain,:IPv6
-    else
-      yield Mapping[protocol][:tables],table,chain,protocol.to_sym
-    end
+    yield Mapping[protocol.to_sym][:tables],table,chain,protocol.to_sym
   end
+
 end
index 542557b7d98fcf128379592dbc54a77793fc438e..830c68abac976c31ca0be9c496de89b95be0981e 100644 (file)
@@ -1,27 +1,16 @@
-
 Puppet::Type.newtype(:firewallchain) do
 
   @doc = <<-EOS
-    This type provides the capability to manage iptables chains and policies on
-    internal chains within puppet.
-  EOS
+    This type provides the capability to manage rule chains for firewalls.
 
-  #InternalChains = /^(PREROUTING|POSTROUTING|BROUTING|INPUT|FORWARD|OUTPUT)$/
-  #Tables = 'NAT|MANGLE|FILTER|RAW|RAWPOST|BROUTE|'
-  ## Technically colons (':') are allowed in table names however it requires
-  ## ruby-1.9 to do a regex to allow a backslash escaping of the colon.
-  ## ruby-1.9 regex:  Nameformat = /^(<table>#{Tables}):(<chain>([^:]*(?<!\\))+):(<protocol>IP(v[46])?|EB)?$/
-  #Nameformat = /^(#{Tables}):([^:]+):(IP(v[46])?|ethernet:)$/
+    Currently this supports only iptables, ip6tables and ebtables on Linux. And
+    provides support for setting the default policy on chains and tables that
+    allow it.
+  EOS
 
   feature :iptables_chain, "The provider provides iptables chain features."
   feature :policy, "Default policy (inbuilt chains only)"
 
-  #autorequire(:firewallchain) do
-  #  if @parameters[:name] =~ /:$/
-  #    [ @parameters[:name] + 'IPv4', @parameters[:name] + 'IPv6']
-  #  end
-  #end
-
   ensurable do
     defaultvalues
     defaultto :present
@@ -30,46 +19,48 @@ Puppet::Type.newtype(:firewallchain) do
   newparam(:name) do
     desc <<-EOS
       The canonical name of the chain.
+
+      For iptables the format must be {chain}:{table}:{protocol}.
     EOS
     isnamevar
 
     validate do |value|
       if value !~ Nameformat then
-        raise ArgumentError, "Inbuilt chains must be in the form {chain}:{table}:{protocol} where {table} is one of FILTER, NAT, MANGLE, RAW, RAWPOST, BROUTE or empty (alias for filter), chain can be anything without colons or one of PREROUTING, POSTROUTING, BROUTING, INPUT, FORWARD, OUTPUT for the inbuilt chains, and {protocol} being empty or IP (both meaning IPv4 and IPv6), IPv4, IPv6, ethernet (ethernet bridging) got '#{value}' table:'#{$1}' chain:'#{$2}' protocol:'#{$3}'"
-      else 
+        raise ArgumentError, "Inbuilt chains must be in the form {table}:{chain}:{protocol} where {table} is one of FILTER, NAT, MANGLE, RAW, RAWPOST, BROUTE or empty (alias for filter), chain can be anything without colons or one of PREROUTING, POSTROUTING, BROUTING, INPUT, FORWARD, OUTPUT for the inbuilt chains, and {protocol} being IPv4, IPv6, ethernet (ethernet bridging) got '#{value}' table:'#{$1}' chain:'#{$2}' protocol:'#{$3}'"
+      else
         table = $1
         chain = $2
         protocol = $3
         case table
-        when /^(FILTER|)$/
+        when 'filter'
           if chain =~ /^(PREROUTING|POSTROUTING|BROUTING)$/
             raise ArgumentError, "INPUT, OUTPUT and FORWARD are the only inbuilt chains that can be used in table 'filter'"
           end
-        when 'MANGLE'
+        when 'mangle'
           if chain =~ InternalChains && chain == 'BROUTING'
             raise ArgumentError, "PREROUTING, POSTROUTING, INPUT, FORWARD and OUTPUT are the only inbuilt chains that can be used in table 'mangle'"
           end
-        when 'NAT'
+        when 'nat'
           if chain =~ /^(BROUTING|INPUT|FORWARD)$/
             raise ArgumentError, "PREROUTING, POSTROUTING and OUTPUT are the only inbuilt chains that can be used in table 'nat'"
           end
           if protocol =~/^(IP(v6)?)?$/
-            raise ArgumentError, "table nat isn't valid in IPv6 (or the default IP which is IPv4 and IPv6). You must specify ':IPv4' as the name suffix"
+            raise ArgumentError, "table nat isn't valid in IPv6. You must specify ':IPv4' as the name suffix"
           end
-        when 'RAW'
+        when 'raw'
           if chain =~ /^(POSTROUTING|BROUTING|INPUT|FORWARD)$/
             raise ArgumentError,'PREROUTING and OUTPUT are the only inbuilt chains in the table \'raw\''
           end
-        when 'BROUTE'
+        when 'broute'
           if protocol != 'ethernet'
             raise ArgumentError,'BROUTE is only valid with protocol \'ethernet\''
           end
           if chain =~ /^PREROUTING|POSTROUTING|INPUT|FORWARD|OUTPUT$/
-            raise ArgumentError,'BROUTING is the only inbuilt chain allowed on on table \'BROUTE\''
+            raise ArgumentError,'BROUTING is the only inbuilt chain allowed on on table \'broute\''
           end
-        end  
-        if chain == 'BROUTING' && ( protocol != 'ethernet' || table!='BROUTE')
-          raise ArgumentError,'BROUTING is the only inbuilt chain allowed on on table \'BROUTE\' with protocol \'ethernet\' i.e. \'BROUTE:BROUTING:enternet\''
+        end
+        if chain == 'BROUTING' && ( protocol != 'ethernet' || table!='broute')
+          raise ArgumentError,'BROUTING is the only inbuilt chain allowed on on table \'BROUTE\' with protocol \'ethernet\' i.e. \'broute:BROUTING:enternet\''
         end
       end
     end
@@ -78,7 +69,7 @@ Puppet::Type.newtype(:firewallchain) do
   newproperty(:policy) do
     desc <<-EOS
       This is the action to when the end of the chain is reached.
-      It can only be set on inbuilt chains ( INPUT, FORWARD, OUTPUT,
+      It can only be set on inbuilt chains (INPUT, FORWARD, OUTPUT,
       PREROUTING, POSTROUTING) and can be one of:
 
       * accept - the packet is accepted
@@ -87,13 +78,14 @@ Puppet::Type.newtype(:firewallchain) do
       * return - the packet is returned to calling (jump) queue
                  or the default of inbuilt chains
     EOS
-    newvalues(:accept, :drop, :queue, :return, :empty)
+    newvalues(:accept, :drop, :queue, :return)
     defaultto do
-      # ethernet chain have an ACCEPT default while other haven't got an allowed value
+      # ethernet chain have an ACCEPT default while other haven't got an
+      # allowed value
       if @resource[:name] =~ /:ethernet$/
         :accept
       else
-        :empty
+        nil
       end
     end
   end
@@ -107,24 +99,27 @@ Puppet::Type.newtype(:firewallchain) do
     protocol = $3
 
     # Check that we're not removing an internal chain
-    if chain =~ InternalChains && value(:ensure).to_s == 'absent'
+    if chain =~ InternalChains && value(:ensure) == :absent
       self.fail "Cannot remove in-built chains"
     end
 
-    if value(:policy) == :empty && protocol == 'ethernet'
+    if value(:policy).nil? && protocol == 'ethernet'
       self.fail "you must set a non-empty policy on all ethernet table chains"
     end
 
     # Check that we're not setting a policy on a user chain
-    if chain !~ InternalChains && value(:policy).to_s != 'empty' && protocol != 'ethernet'
-      self.fail "policy can only be set on in-built chains (with the exceptionn of ethernet chains) (table:#{table} chain:#{chain} protocol:#{protocol})"
+    if chain !~ InternalChains &&
+      !value(:policy).nil? &&
+      protocol != 'ethernet'
+
+      self.fail "policy can only be set on in-built chains (with the exception of ethernet chains) (table:#{table} chain:#{chain} protocol:#{protocol})"
     end
+
     # no DROP policy on nat table
     if table == 'nat' &&
-       value(:policy).to_s == 'DROP'
+      value(:policy) == :drop
+
       self.fail 'The "nat" table is not intended for filtering, the use of DROP is therefore inhibited'
     end
   end
 end
-
index 3c1af07aa82b05ce2afe2b7c4e7f4ad0ce5509e0..143e1e63b45bf5196afbb10c6ddc7adf2fc0d979 100755 (executable)
@@ -38,20 +38,10 @@ describe 'iptables chain provider detection' do
 
     # Create a resource instance and make sure the provider is iptables
     resource = Puppet::Type.type(:firewallchain).new({
-      :name => ':test:',
+      :name => 'filter:test:IPv4',
     })
     resource.provider.class.to_s.should == "Puppet::Type::Firewallchain::ProviderIptables_chain"
   end
-
-  it "should raise a default provider error when there are no commands" do
-    # Stub all commands lookups so they return nothing 
-    exists.any_instance.stubs(:which).returns false
-
-    # Instantiate a resource instance and make sure it raises an exception
-    lambda { resource = Puppet::Type.type(:firewallchain).new({ 
-      :name => ':test:' }) }.should raise_error(Puppet::DevError, 
-      "Could not find a default provider for firewallchain")
-  end
 end
 
 describe 'iptables chain provider' do
@@ -68,7 +58,7 @@ describe 'iptables chain provider' do
     provider.stubs(:command).with(:iptables_save).returns "/sbin/iptables-save"
     provider.stubs(:command).with(:ip6tables_save).returns "/sbin/ip6tables-save"
   end
-  
+
   it 'should be able to get a list of existing rules' do
     # Pretend to return nil from iptables
     provider.expects(:execute).with(['/sbin/ebtables-save']).returns("")
@@ -99,7 +89,7 @@ describe 'iptables chain resource parsing' do
                 'NAT:OUTPUT:ethernet',
                 'NAT:POSTROUTING:ethernet',
                ]
-    provider.expects(:execute).with(['/sbin/ebtables-save']).returns('
+    provider.stubs(:execute).with(['/sbin/ebtables-save']).returns('
 *broute
 :BROUTING ACCEPT
 :broute ACCEPT
@@ -136,7 +126,7 @@ describe 'iptables chain resource parsing' do
      'NAT:mangle:IPv4',
      ':$5()*&%\'"^$): :IPv4',
     ]
-    provider.expects(:execute).with(['/sbin/iptables-save']).returns('
+    provider.stubs(:execute).with(['/sbin/iptables-save']).returns('
 # Generated by iptables-save v1.4.9 on Mon Jan  2 01:20:06 2012
 *raw
 :PREROUTING ACCEPT [12:1780]
@@ -185,7 +175,7 @@ COMMIT
       ':OUTPUT:IPv6',
       ':test:IPv6',
     ]
-    provider.expects(:execute).with(['/sbin/ip6tables-save']).returns('
+    provider.stubs(:execute).with(['/sbin/ip6tables-save']).returns('
 # Generated by ip6tables-save v1.4.9 on Mon Jan  2 01:31:39 2012
 *raw
 :PREROUTING ACCEPT [2173:489241]
@@ -218,7 +208,7 @@ COMMIT
     ip6tables.each { |name| @all += [ name[0..-3], name[0..-5] ] }
   end
 
-  it 'should have  all in parsed resources' do
+  it 'should have all in parsed resources' do
     provider.instances.each do |resource|
       @all.include?(resource.name)
     end
index 23ce0a89d18544ee0c5afb6625ddf2fdf2e4d876..2bb031f80e350e78008b9876ec73ebac1c6f9bdd 100755 (executable)
@@ -5,41 +5,43 @@ require 'spec_helper'
 firewallchain = Puppet::Type.type(:firewallchain)
 
 describe firewallchain do
-  before :each do
-    @class = firewallchain
-    @provider = stub 'provider'
-    @provider.stubs(:name).returns(:iptables_chain)
-    Puppet::Type::Firewallchain.stubs(:defaultprovider).returns @provider
-    @resource = @class.new({:name => ':INPUT:', :policy => :accept })
-  end
+  let(:klass) { firewallchain }
+  let(:provider) {
+    prov = stub 'provider'
+    prov.stubs(:name).returns(:iptables_chain)
+    prov
+  }
+  let(:resource) {
+    Puppet::Type::Firewallchain.stubs(:defaultprovider).returns provider
+    klass.new({:name => 'filter:INPUT:IPv4', :policy => :accept })
+  }
 
   it 'should have :name be its namevar' do
-    @class.key_attributes.should == [:name]
+    klass.key_attributes.should == [:name]
   end
 
   describe ':name' do
-    {'' => ['INPUT','OUTPUT','FORWARD'],
-     'NAT' => ['PREROUTING', 'POSTROUTING', 'OUTPUT'],
-     'MANGLE' => [ 'PREROUTING', 'POSTROUTING', 'INPUT', 'FORWARD', 'OUTPUT' ],
-     'FILTER' => ['INPUT','OUTPUT','FORWARD'],
-     'RAW' => [ 'PREROUTING', 'OUTPUT'],
-     'BROUTE' => ['BROUTING']
+    {'nat' => ['PREROUTING', 'POSTROUTING', 'OUTPUT'],
+     'mangle' => [ 'PREROUTING', 'POSTROUTING', 'INPUT', 'FORWARD', 'OUTPUT' ],
+     'filter' => ['INPUT','OUTPUT','FORWARD'],
+     'raw' => [ 'PREROUTING', 'OUTPUT'],
+     'broute' => ['BROUTING']
     }.each_pair do |table, allowedinternalchains|
-      ['', 'IPv4', 'IPv6', 'IP', 'ethernet'].each do |protocol|
+      ['IPv4', 'IPv6', 'ethernet'].each do |protocol|
         [ 'test', '$5()*&%\'"^$09):' ].each do |chainname|
           name = "#{table}:#{chainname}:#{protocol}"
-          if table == 'NAT' && ['IPv6','','IP'].include?(protocol)
+          if table == 'nat' && protocol == 'IPv6'
             it "should fail #{name}" do
-              lambda { @resource[:name] = name }.should raise_error(Puppet::Error)
+              expect { resource[:name] = name }.to raise_error(Puppet::Error)
             end
-          elsif protocol != 'ethernet' && table == 'BROUTE'
+          elsif protocol != 'ethernet' && table == 'broute'
             it "should fail #{name}" do
-              lambda { @resource[:name] = name }.should raise_error(Puppet::Error)
+              expect { resource[:name] = name }.to raise_error(Puppet::Error)
             end
           else
             it "should accept name #{name}" do
-              @resource[:name] = name
-              @resource[:name].should == name
+              resource[:name] = name
+              resource[:name].should == name
             end
           end
         end # chainname
@@ -49,17 +51,19 @@ describe firewallchain do
         name = table + ':' + internalchain + ':'
         if internalchain == 'BROUTING'
           name += 'ethernet'
-        elsif table == 'NAT'
+        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
+            resource[:name] = name
+            resource[:name].should == name
           end
         else
           it "should fail #{name}" do
-            lambda { @resource[:name] = name }.should raise_error(Puppet::Error)
+            expect { resource[:name] = name }.to raise_error(Puppet::Error)
           end
         end
       end # internalchain
@@ -67,34 +71,34 @@ describe firewallchain do
     end # table, allowedinternalchainnames
 
     it 'should fail with invalid table names' do
-      lambda { @resource[:name] = 'wrongtablename:test:' }.should raise_error(Puppet::Error)
+      expect { resource[:name] = 'wrongtablename:test:' }.to raise_error(Puppet::Error)
     end
 
     it 'should fail with invalid protocols names' do
-      lambda { @resource[:name] = ':test:IPv5' }.should raise_error(Puppet::Error)
+      expect { resource[:name] = ':test: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
+        resource[:policy] = policy
+        resource[:policy].should == policy
       end
     end
 
     it 'should fail when value is not recognized' do
-      lambda { @resource[:policy] = 'not valid' }.should raise_error(Puppet::Error)
+      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
-        lambda { @class.new({:name => ':testchain:', :policy => policy }) }.should raise_error(Puppet::Error)
+        expect { klass.new({:name => 'filter:testchain:IPv4', :policy => policy }) }.to raise_error(Puppet::Error)
       end
       it "non-inbuilt chains can accept policies on protocol = ethernet (policy #{policy})" do
-        @class.new({:name => ':testchain:ethernet', :policy => policy }).should be_instance_of(@provider)
+        klass.new({:name => 'filter:testchain:ethernet', :policy => policy }).should be_instance_of(@provider)
       end
     end