Skip to content

Commit

Permalink
[#879] -- OS.EnableFirewall=y breaks load balanced sets probing
Browse files Browse the repository at this point in the history
Signed-off-by: Brendan Dixon <brendandixon@me.com>
  • Loading branch information
brendandixon committed Sep 13, 2017
1 parent a146f27 commit 34c10d5
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 34 deletions.
76 changes: 54 additions & 22 deletions azurelinuxagent/common/osutil/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,21 @@
# Requires Python 2.4+ and Openssl 1.0+
#

import array
import base64
import datetime
import fcntl
import glob
import multiprocessing
import os
import platform
import pwd
import re
import shutil
import socket
import array
import struct
import sys
import time
import pwd
import fcntl
import base64
import glob
import datetime

import azurelinuxagent.common.logger as logger
import azurelinuxagent.common.conf as conf
Expand Down Expand Up @@ -58,6 +59,7 @@
FIREWALL_ACCEPT = "iptables {0} -t security -{1} OUTPUT -d {2} -p tcp -m owner --uid-owner {3} -j ACCEPT"
FIREWALL_DROP = "iptables {0} -t security -{1} OUTPUT -d {2} -p tcp -j DROP"
FIREWALL_LIST = "iptables {0} -t security -L"
FIREWALL_FLUSH = "iptables {0} -t security --flush"

_enable_firewall = True

Expand All @@ -74,6 +76,47 @@ def __init__(self):
self.selinux = None
self.disable_route_warning = False

def get_firewall_will_wait(self):
# Determine if iptables will serialize access
rc, output = shellutil.run_get_output(IPTABLES_VERSION)
if rc != 0:
msg = "Unable to determine version of iptables"
logger.warn(msg)
raise Exception(msg)

m = IPTABLES_VERSION_PATTERN.match(output)
if m is None:
msg = "iptables did not return version information"
logger.warn(msg)
raise Exception(msg)

wait = "-w" \
if FlexibleVersion(m.group(1)) >= IPTABLES_LOCKING_VERSION \
else ""
return wait

def remove_firewall(self):
# If a previous attempt threw an exception, do not retry
global _enable_firewall
if not _enable_firewall:
return False

try:
wait = self.get_firewall_will_wait()

flush_rule = FIREWALL_FLUSH.format(wait)
if shellutil.run(flush_rule, chk_err=False) != 0:
logger.warn("Failed to flush firewall")

return True

except Exception as e:
_enable_firewall = False
logger.info("Unable to flush firewall -- "
"no further attempts will be made: "
"{0}".format(ustr(e)))
return False

def enable_firewall(self, dst_ip=None, uid=None):

# If a previous attempt threw an exception, do not retry
Expand All @@ -87,22 +130,7 @@ def enable_firewall(self, dst_ip=None, uid=None):
logger.warn(msg)
raise Exception(msg)

# Determine if iptables will serialize access
rc, output = shellutil.run_get_output(IPTABLES_VERSION)
if rc != 0:
msg = "Unable to determine version of iptables"
logger.warn(msg)
raise Exception(msg)

m = IPTABLES_VERSION_PATTERN.match(output)
if m is None:
msg = "iptables did not return version information"
logger.warn(msg)
raise Exception(msg)

wait = "-w" \
if FlexibleVersion(m.group(1)) >= IPTABLES_LOCKING_VERSION \
else ""
wait = self.get_firewall_will_wait()

# If the DROP rule exists, make no changes
drop_rule = FIREWALL_DROP.format(wait, "C", dst_ip)
Expand Down Expand Up @@ -964,3 +992,7 @@ def get_processor_cores(self):

def check_pid_alive(self, pid):
return pid is not None and os.path.isdir(os.path.join('/proc', pid))

@property
def is_64bit(self):
return sys.maxsize > 2**32
25 changes: 14 additions & 11 deletions azurelinuxagent/ga/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,17 +76,20 @@ def monitor(self):
while not self.stopped:
self.osutil.remove_rules_files()

if conf.enable_firewall():
success = self.osutil.enable_firewall(
dst_ip=protocol.endpoint,
uid=os.getuid())
add_periodic(
logger.EVERY_HOUR,
AGENT_NAME,
version=CURRENT_VERSION,
op=WALAEventOperation.Firewall,
is_success=success,
log_event=True)
# Disable setting firewall for now, regardless of configuration switch
# if conf.enable_firewall():
# success = self.osutil.enable_firewall(
# dst_ip=protocol.endpoint,
# uid=os.getuid())
# add_periodic(
# logger.EVERY_HOUR,
# AGENT_NAME,
# version=CURRENT_VERSION,
# op=WALAEventOperation.Firewall,
# is_success=success,
# log_event=True)

self.osutil.remove_firewall()

timeout = conf.get_root_device_scsi_timeout()
if timeout is not None:
Expand Down
25 changes: 24 additions & 1 deletion tests/common/osutil/test_default.py
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,6 @@ def test_enable_firewall_skips_if_disabled(self, mock_run, mock_output, mock_uid
dst = '1.2.3.4'
uid = 42
version = "iptables v{0}".format(osutil.IPTABLES_LOCKING_VERSION)
wait = "-w"

mock_run.side_effect = [1, 0, 0]
mock_output.side_effect = [(0, version), (0, "Output")]
Expand All @@ -613,5 +612,29 @@ def test_enable_firewall_skips_if_disabled(self, mock_run, mock_output, mock_uid
mock_uid.assert_not_called()
self.assertFalse(osutil._enable_firewall)

@patch('os.getuid', return_value=42)
@patch('azurelinuxagent.common.utils.shellutil.run_get_output')
@patch('azurelinuxagent.common.utils.shellutil.run')
def test_remove_firewall(self, mock_run, mock_output, mock_uid):
osutil._enable_firewall = True
util = osutil.DefaultOSUtil()

dst = '1.2.3.4'
uid = 42
version = "iptables v{0}".format(osutil.IPTABLES_LOCKING_VERSION)
wait = "-w"

mock_run.side_effect = [0, 0]
mock_output.side_effect = [(0, version), (0, "Output")]
self.assertTrue(util.remove_firewall())

mock_run.assert_has_calls([
call(osutil.FIREWALL_FLUSH.format(wait), chk_err=False)
])
mock_output.assert_has_calls([
call(osutil.IPTABLES_VERSION)
])
self.assertTrue(osutil._enable_firewall)

if __name__ == '__main__':
unittest.main()

0 comments on commit 34c10d5

Please sign in to comment.