]> review.fuel-infra Code Review - puppet-modules/puppetlabs-firewall.git/commitdiff
(CONT-242) Fix duplicate rule detection
authordavid22swan <david.swan@puppet.com>
Wed, 7 Jun 2023 16:47:59 +0000 (17:47 +0100)
committerdavid22swan <david.swan@puppet.com>
Wed, 7 Jun 2023 16:48:13 +0000 (17:48 +0100)
This was previously accomplished b retrieving the full list of rules each time a rule was set in order to check it was unique. This was to allow the user to choose the response to a duplicate rule being found.

However this caused a massive slowdown within certain module runs and as such we have changed the the location of the check, so that it instead runs a check for any duplicates when retrieving the current rules prior to any updates being made.

As an effect of this the user is now unable to choose the response to a duplicate rule being found, however wee feel that this is a fair tradeoff for the increased speed and that the response that we have chosen is the correct one.

README.md
REFERENCE.md
lib/puppet/provider/firewall/iptables.rb
lib/puppet/type/firewall.rb
spec/acceptance/firewall_duplicate_comment_spec.rb

index f1985e3665e7247fca41c0cbcd2870d91789a6aa..3b0519d60281715c91a9f2f1b5ad27b11e6fc2cd 100644 (file)
--- a/README.md
+++ b/README.md
@@ -394,17 +394,9 @@ firewall {'666 for NFLOG':
 
 It is possible for an unmanaged rule to exist on the target system that has the same comment as the rule specified in the manifest. This configuration is not supported by the firewall module.
 
-In the event of a duplicate rule, the module will by default display a warning message notifying the user that it has found a duplicate but will continue to update the resource.
-
-This behaviour is configurable via the `onduplicaterulebehaviour` parameter. Users can choose from the following behaviours:
-
-* `ignore` - The duplicate rule is ignored and any updates to the resource will continue unaffected.
-* `warn` - The duplicate rule is logged as a warning and any updates to the resource will continue unaffected.
-* `error` - The duplicate rule is logged as an error and any updates to the resource will be skipped.
-
-With either the `ignore` or `warn` (default) behaviour, Puppet may create another duplicate rule.
-To prevent this behavior and report the resource as failing during the Puppet run, specify the `error` behaviour.
+In the event of a duplicate rule, the module will throw an error message notifying the user that it has found a duplicate and halt in it's update.
 
+This behaviour was previously configurable via the `onduplicaterulebehaviour` parameter. However the implementation of this resulted in a massive slowdown of the module runs and so this has been removed infavour of a simple error being thrown whenever a duplicate is detected.
 ### Additional information
 
 Access the inline documentation:
index d2f8d17d86835f41fe6e0caac83dbc9681583248..004605396b502835a5221b42cafe88dc51f79dd3 100644 (file)
@@ -1382,7 +1382,6 @@ The following parameters are available in the `firewall` type.
 
 * [`line`](#-firewall--line)
 * [`name`](#-firewall--name)
-* [`onduplicaterulebehaviour`](#-firewall--onduplicaterulebehaviour)
 * [`provider`](#-firewall--provider)
 
 ##### <a name="-firewall--line"></a>`line`
@@ -1404,24 +1403,6 @@ so make sure you prefix the rule with a number:
 Depending on the provider, the name of the rule can be stored using
 the comment feature of the underlying firewall subsystem.
 
-##### <a name="-firewall--onduplicaterulebehaviour"></a>`onduplicaterulebehaviour`
-
-Valid values: `ignore`, `warn`, `error`
-
-In certain situations it is possible for an unmanaged rule to exist
-on the target system that has the same comment as the rule
-specified in the manifest.
-
-This setting determines what happens when such a duplicate is found.
-
-It offers three options:
-
-  * ignore - The duplicate rule is ignored and any updates to the resource will continue unaffected.
-  * warn - The duplicate rule is logged as a warning and any updates to the resource will continue unaffected.
-  * error - The duplicate rule is logged as an error and any updates to the resource will be skipped.
-
-Default value: `warn`
-
 ##### <a name="-firewall--provider"></a>`provider`
 
 The specific backend to use for this `firewall` resource. You will seldom need to specify this --- Puppet will usually
index 9d26f03a454e931bec36292dd1461fdc183ef9b3..263e7dd3a2498cc1c555bd38b037c4f4bd313724 100644 (file)
@@ -410,29 +410,9 @@ Puppet::Type.type(:firewall).provide :iptables, parent: Puppet::Provider::Firewa
   end
 
   def exists?
-    if duplicate_rule?(@property_hash[:name])
-      core_message = "Duplicate rule found for #{@property_hash[:name]}."
-      case @resource.parameters[:onduplicaterulebehaviour].value
-      when :error
-        raise   "#{core_message} Skipping update."
-      when :warn
-        warning "#{core_message}. This may add an additional rule to the system."
-      when :ignore
-        debug "#{core_message}. This may add an additional rule to the system."
-      end
-    end
-
     properties[:ensure] != :absent
   end
 
-  def duplicate_rule?(rule)
-    rules = self.class.instances
-    system_rule_count = Hash.new(0)
-    rules.each { |r| system_rule_count[r.name] += 1 }
-    duplicate_rules = rules.select { |r| system_rule_count[r.name] > 1 }
-    duplicate_rules.select { |r| r.name == rule }.any?
-  end
-
   # Flush the property hash once done.
   def flush
     debug('[flush]')
@@ -448,6 +428,8 @@ Puppet::Type.type(:firewall).provide :iptables, parent: Puppet::Provider::Firewa
     debug '[instances]'
     table = nil
     rules = []
+    # Used for detecting duplicate rules
+    duplicate_rules = []
     counter = 1
 
     # String#lines would be nice, but we need to support Ruby 1.8.5
@@ -459,6 +441,8 @@ Puppet::Type.type(:firewall).provide :iptables, parent: Puppet::Provider::Firewa
         else
           hash = rule_to_hash(line, table, counter)
           if hash
+            raise "Duplicate rule found for #{hash[:name]}. Skipping update." if duplicate_rules.include?(hash[:name])
+            duplicate_rules << hash[:name]
             rules << new(hash)
             counter += 1
           end
index 86af41b314e15ff140fe92b76f996af6895a9239..4d0205cee489e6807cfb40dd4870f31ff6e30523 100644 (file)
@@ -236,24 +236,6 @@ Puppet::Type.newtype(:firewall) do
     newvalues(%r{^\d+[[:graph:][:space:]]+$})
   end
 
-  newparam(:onduplicaterulebehaviour) do
-    desc <<-PUPPETCODE
-      In certain situations it is possible for an unmanaged rule to exist
-      on the target system that has the same comment as the rule
-      specified in the manifest.
-
-      This setting determines what happens when such a duplicate is found.
-
-      It offers three options:
-
-        * ignore - The duplicate rule is ignored and any updates to the resource will continue unaffected.
-        * warn - The duplicate rule is logged as a warning and any updates to the resource will continue unaffected.
-        * error - The duplicate rule is logged as an error and any updates to the resource will be skipped.
-    PUPPETCODE
-    newvalues(:ignore, :warn, :error)
-    defaultto :warn
-  end
-
   newproperty(:action) do
     desc <<-PUPPETCODE
       This is the action to perform on a match. Can be one of:
index e019a45972abb26d83c2e688e4cb4a126c0a5f2a..93251d07b1a2c36d97322efe9a8e110e002b2ea6 100644 (file)
@@ -2,8 +2,19 @@
 
 require 'spec_helper_acceptance'
 
-def make_manifest(behaviour)
-  pp = <<-PUPPETCODE
+describe 'firewall - duplicate comments' do
+  before(:all) do
+    if os[:family] == 'ubuntu' || os[:family] == 'debian'
+      update_profile_file
+    end
+  end
+
+  after(:each) do
+    iptables_flush_all_tables
+  end
+
+  context 'when a duplicate comment is found' do
+    pp = <<-PUPPETCODE
     class { 'firewall': }
     resources { 'firewall':
       purge => true,
@@ -14,61 +25,15 @@ def make_manifest(behaviour)
       dport   => '550',
       action => accept,
       destination => '192.168.2.0/24',
-      onduplicaterulebehaviour => #{behaviour}
     }
     PUPPETCODE
 
-  pp
-end
-
-describe 'firewall - duplicate comments' do
-  before(:all) do
-    if os[:family] == 'ubuntu' || os[:family] == 'debian'
-      update_profile_file
-    end
-  end
-
-  before(:each) do
-    run_shell('iptables -I INPUT -m state --state NEW -m tcp -p tcp --dport 551 -j ACCEPT -m comment --comment "550 destination"')
-  end
-
-  after(:each) do
-    iptables_flush_all_tables
-  end
-
-  context 'when onduplicateerrorhevent is set to error' do
     it 'raises an error' do
       run_shell('iptables -I INPUT -m state --state NEW -m tcp -p tcp --dport 551 -j ACCEPT -m comment --comment "550 destination"')
-      pp = make_manifest('error')
-
-      apply_manifest(pp) do |r|
-        expect(r.stderr).to include('Error: /Stage[main]/Main/Firewall[550 destination]: Could not evaluate: Duplicate rule found for 550 destination. Skipping update.')
-      end
-    end
-  end
-
-  context 'when onduplicateerrorhevent is set to warn' do
-    run_shell('iptables -I INPUT -m state --state NEW -m tcp -p tcp --dport 551 -j ACCEPT -m comment --comment "550 destination"')
-
-    it 'warns and continues' do
-      run_shell('iptables -I INPUT -m state --state NEW -m tcp -p tcp --dport 551 -j ACCEPT -m comment --comment "550 destination"')
-      pp = make_manifest('warn')
-
-      apply_manifest(pp) do |r|
-        expect(r.stderr).to include('Warning: Firewall[550 destination](provider=iptables): Duplicate rule found for 550 destination.. This may add an additional rule to the system.')
-      end
-    end
-  end
-
-  context 'when onduplicateerrorhevent is set to ignore' do
-    run_shell('iptables -I INPUT -m state --state NEW -m tcp -p tcp --dport 551 -j ACCEPT -m comment --comment "550 destination"')
-
-    it 'continues silently' do
-      run_shell('iptables -I INPUT -m state --state NEW -m tcp -p tcp --dport 551 -j ACCEPT -m comment --comment "550 destination"')
-      pp = make_manifest('ignore')
+      run_shell('iptables -I INPUT -m state --state NEW -m tcp -p tcp --dport 552 -j ACCEPT -m comment --comment "550 destination"')
 
       apply_manifest(pp) do |r|
-        expect(r.stderr).to be_empty
+        expect(r.stderr).to include('Duplicate rule found for 550 destination. Skipping update.')
       end
     end
   end