Author: arkurth
Date: Tue Jul 11 20:50:48 2017
New Revision: 1801653

URL: http://svn.apache.org/viewvc?rev=1801653&view=rev
Log:
VCL-1056
Added iptables.pm::_execute_iptables subroutine. It simply calls 
$self->os->execute() and checks the output for text indicating another process 
has an xtables lock.

Changed all existing calls from $self->os->execute() to 
$self->_execute_iptables();

Modified:
    vcl/trunk/managementnode/lib/VCL/Module/OS/Linux/firewall/iptables.pm

Modified: vcl/trunk/managementnode/lib/VCL/Module/OS/Linux/firewall/iptables.pm
URL: 
http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/Module/OS/Linux/firewall/iptables.pm?rev=1801653&r1=1801652&r2=1801653&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/Module/OS/Linux/firewall/iptables.pm 
(original)
+++ vcl/trunk/managementnode/lib/VCL/Module/OS/Linux/firewall/iptables.pm Tue 
Jul 11 20:50:48 2017
@@ -89,22 +89,6 @@ sub initialize {
                return 0;
        }
        
-       # Make sure 'iptables -L' works, it won't if the management node does 
not have root access
-       # This is likely for computers provisioned by Lab.pm
-       # The iptables command may exist but generates this error:
-       #    iptables v1.4.7: can't initialize iptables table `filter': 
Permission denied (you must be root)
-       #    Perhaps iptables or your kernel needs to be upgraded.
-       my $command = "iptables -L";
-       my ($exit_status, $output) = $self->os->execute($command);
-       if (!defined($output)) {
-               notify($ERRORS{'WARNING'}, 0, ref($self) . " object not 
initialized to control $computer_name, failed to execute command to test if 
management node has access to configure iptables on the computer");
-               return;
-       }
-       elsif (grep(/(can't initialize|Permission denied|you must be root)/i, 
@$output)) {
-               notify($ERRORS{'DEBUG'}, 0, ref($self) . " object not 
initialized to control $computer_name, iptables command exists but cannot be 
controlled by the management node user:\n" . join("\n", @$output));
-               return 0;
-       }
-       
        notify($ERRORS{'DEBUG'}, 0, ref($self) . " object initialized to 
control $computer_name");
        return 1;
 }
@@ -773,7 +757,7 @@ sub _insert_rule {
        my $computer_name = $self->data->get_computer_hostname();
        
        my $command = "/sbin/iptables --insert $chain_name --table $table_name 
$argument_string";
-       my ($exit_status, $output) = $self->os->execute($command, 0);
+       my ($exit_status, $output) = $self->_execute_iptables($command);
        if (!defined($output)) {
                notify($ERRORS{'WARNING'}, 0, "failed to execute command on 
$computer_name: $command");
                return;
@@ -1121,7 +1105,7 @@ sub _delete_rule {
        my $computer_name = $self->data->get_computer_hostname();
        
        my $command = "/sbin/iptables --delete $chain_name -t $table_name 
$rule_specification_string";
-       my ($exit_status, $output) = $self->os->execute($command, 0);
+       my ($exit_status, $output) = $self->_execute_iptables($command);
        if (!defined($output)) {
                notify($ERRORS{'WARNING'}, 0, "failed to execute command on 
$computer_name: $command");
                return;
@@ -1208,7 +1192,7 @@ sub create_chain {
        my $semaphore = $self->get_iptables_semaphore();
        
        my $command = "/sbin/iptables --new-chain $chain_name --table 
$table_name";
-       my ($exit_status, $output) = $self->os->execute($command, 0);
+       my ($exit_status, $output) = $self->_execute_iptables($command);
        if (!defined($output)) {
                notify($ERRORS{'WARNING'}, 0, "failed to execute command 
$computer_name: $command");
                return;
@@ -1280,7 +1264,7 @@ sub delete_chain {
                my $command = "/sbin/iptables --delete-chain $chain_name 
--table $table_name";
                
                my $semaphore = $self->get_iptables_semaphore();
-               my ($exit_status, $output) = $self->os->execute($command, 0);
+               my ($exit_status, $output) = $self->_execute_iptables($command);
                if (!defined($output)) {
                        notify($ERRORS{'WARNING'}, 0, "failed to execute 
command $computer_name: $command");
                        return;
@@ -1484,7 +1468,7 @@ sub flush_chain {
        my $command = "/sbin/iptables --flush $chain_name --table $table_name";
        
        my $semaphore = $self->get_iptables_semaphore();
-       my ($exit_status, $output) = $self->os->execute($command, 0);
+       my ($exit_status, $output) = $self->_execute_iptables($command);
        if (!defined($output)) {
                notify($ERRORS{'WARNING'}, 0, "failed to execute command 
$computer_name: $command");
                return;
@@ -1569,7 +1553,7 @@ sub get_table_info {
        my @lines;
        
        my $command = "/sbin/iptables --list-rules --table $table_name";
-       my ($exit_status, $output) = $self->os->execute($command, 0);
+       my ($exit_status, $output) = $self->_execute_iptables($command);
        if (!defined($output)) {
                notify($ERRORS{'WARNING'}, 0, "failed to execute command 
$computer_name: $command");
                return;
@@ -2396,7 +2380,7 @@ sub save_configuration {
        # IMPORTANT: don't simply redirect the output to the file
        # If iptables is stopped or else the previously saved configuration 
will be overwritten
        my $command = '/sbin/iptables-save';
-       my ($exit_status, $output) = $self->os->execute($command, 0);
+       my ($exit_status, $output) = $self->_execute_iptables($command);
        if (!defined($output)) {
                notify($ERRORS{'WARNING'}, 0, "failed to execute command to 
save iptables configuration on $computer_name");
                return;
@@ -2628,6 +2612,55 @@ sub nat_delete_orphaned_reservation_chai
 }
 
 #//////////////////////////////////////////////////////////////////////////////
+
+=head2 _execute_iptables
+
+ Parameters  : $iptables_command, $display_output (optional)
+ Returns     : ($exit_status, $output)
+ Description : Wrapper subroutine to execute iptables commands. This executes 
an
+               iptables command and checks the output for the following error:
+               "Another app is currently holding the xtables lock."
+               
+               If ancountered, up to 6 attempts is made to execute the iptables
+               command. A progressive delay occurs between each attempt. The
+               delay is 5 seconds longer for each attempt.
+
+=cut
+
+sub _execute_iptables {
+       my $self = shift;
+       if (ref($self) !~ /VCL::Module/i) {
+               notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a 
function, it must be called as a class method");
+               return 0;
+       }
+       
+       my ($iptables_command, $display_output) = @_;
+       if (!defined($iptables_command)) {
+               notify($ERRORS{'WARNING'}, 0, "iptables command argument was 
not supplied");
+               return;
+       }
+       
+       $display_output = 0 unless defined($display_output);
+       
+       my $computer_name = $self->data->get_computer_hostname();
+       
+       my $attempt_limit = 6;
+       for (my $attempt = 1; $attempt <= $attempt_limit; $attempt++) {
+               my ($exit_status, $output) = 
$self->os->execute($iptables_command, $display_output);
+               if (defined($output) && $attempt < $attempt_limit) {
+                       # Another app is currently holding the xtables lock. 
Perhaps you want to use the -w option?
+                       if ($exit_status ne 0 && grep(/xtables lock/, 
@$output)) {
+                               my $sleep_seconds = ($attempt * 5);
+                               notify($ERRORS{'DEBUG'}, 0, "attempt 
$attempt/$attempt_limit: unable to execute iptables command on $computer_name 
becuase another process is holding an xtables lock, waiting for $sleep_seconds 
seconds before attempting command again, command: '$iptables_command', output:" 
. (scalar(@$output) > 1 ? "\n" . join("\n", @$output) : " '" . join("\n", 
@$output) . "'"));
+                               sleep_uninterrupted($sleep_seconds);
+                               next;
+                       }
+               }
+               return ($exit_status, $output);
+       }
+}
+
+#//////////////////////////////////////////////////////////////////////////////
 
 =head2 DESTROY
 


Reply via email to