# Copyright 2012 Locaweb. # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os import sys import fixtures import mock from oslo_config import cfg import testtools from neutron._i18n import _ from neutron.agent.linux import iptables_comments as ic from neutron.agent.linux import iptables_manager from neutron.agent.linux import utils as linux_utils from neutron.common import constants from neutron.common import exceptions as n_exc from neutron.tests import base from neutron.tests import tools IPTABLES_ARG = {'bn': iptables_manager.binary_name, 'snat_out_comment': ic.SNAT_OUT, 'filter_rules': '', 'mark': constants.ROUTER_MARK_MASK} NAT_TEMPLATE = ('# Generated by iptables_manager\n' '*nat\n' ':OUTPUT - [0:0]\n' ':POSTROUTING - [0:0]\n' ':PREROUTING - [0:0]\n' ':neutron-postrouting-bottom - [0:0]\n' ':%(bn)s-OUTPUT - [0:0]\n' ':%(bn)s-POSTROUTING - [0:0]\n' ':%(bn)s-PREROUTING - [0:0]\n' ':%(bn)s-float-snat - [0:0]\n' ':%(bn)s-snat - [0:0]\n' '-I OUTPUT 1 -j %(bn)s-OUTPUT\n' '-I POSTROUTING 1 -j %(bn)s-POSTROUTING\n' '-I POSTROUTING 2 -j neutron-postrouting-bottom\n' '-I PREROUTING 1 -j %(bn)s-PREROUTING\n' '-I neutron-postrouting-bottom 1 -j %(bn)s-snat\n' '-I %(bn)s-snat 1 -j ' '%(bn)s-float-snat\n' 'COMMIT\n' '# Completed by iptables_manager\n') NAT_DUMP = NAT_TEMPLATE % IPTABLES_ARG FILTER_TEMPLATE = ('# Generated by iptables_manager\n' '*filter\n' ':FORWARD - [0:0]\n' ':INPUT - [0:0]\n' ':OUTPUT - [0:0]\n' ':neutron-filter-top - [0:0]\n' ':%(bn)s-FORWARD - [0:0]\n' ':%(bn)s-INPUT - [0:0]\n' ':%(bn)s-OUTPUT - [0:0]\n' ':%(bn)s-local - [0:0]\n' '-I FORWARD 1 -j neutron-filter-top\n' '-I FORWARD 2 -j %(bn)s-FORWARD\n' '-I INPUT 1 -j %(bn)s-INPUT\n' '-I OUTPUT 1 -j neutron-filter-top\n' '-I OUTPUT 2 -j %(bn)s-OUTPUT\n' '-I neutron-filter-top 1 -j %(bn)s-local\n' 'COMMIT\n' '# Completed by iptables_manager\n') FILTER_DUMP = FILTER_TEMPLATE % IPTABLES_ARG FILTER_WITH_RULES_TEMPLATE = ( '# Generated by iptables_manager\n' '*filter\n' ':FORWARD - [0:0]\n' ':INPUT - [0:0]\n' ':OUTPUT - [0:0]\n' ':neutron-filter-top - [0:0]\n' ':%(bn)s-FORWARD - [0:0]\n' ':%(bn)s-INPUT - [0:0]\n' ':%(bn)s-OUTPUT - [0:0]\n' ':%(bn)s-filter - [0:0]\n' ':%(bn)s-local - [0:0]\n' '-I FORWARD 1 -j neutron-filter-top\n' '-I FORWARD 2 -j %(bn)s-FORWARD\n' '-I INPUT 1 -j %(bn)s-INPUT\n' '-I OUTPUT 1 -j neutron-filter-top\n' '-I OUTPUT 2 -j %(bn)s-OUTPUT\n' '-I neutron-filter-top 1 -j %(bn)s-local\n' '%(filter_rules)s' 'COMMIT\n' '# Completed by iptables_manager\n') COMMENTED_NAT_DUMP = ( '# Generated by iptables_manager\n' '*nat\n' ':OUTPUT - [0:0]\n' ':POSTROUTING - [0:0]\n' ':PREROUTING - [0:0]\n' ':neutron-postrouting-bottom - [0:0]\n' ':%(bn)s-OUTPUT - [0:0]\n' ':%(bn)s-POSTROUTING - [0:0]\n' ':%(bn)s-PREROUTING - [0:0]\n' ':%(bn)s-float-snat - [0:0]\n' ':%(bn)s-snat - [0:0]\n' '-I OUTPUT 1 -j %(bn)s-OUTPUT\n' '-I POSTROUTING 1 -j %(bn)s-POSTROUTING\n' '-I POSTROUTING 2 -j neutron-postrouting-bottom\n' '-I PREROUTING 1 -j %(bn)s-PREROUTING\n' '-I neutron-postrouting-bottom 1 ' '-m comment --comment "%(snat_out_comment)s" -j %(bn)s-snat\n' '-I %(bn)s-snat 1 -j ' '%(bn)s-float-snat\n' 'COMMIT\n' '# Completed by iptables_manager\n' % IPTABLES_ARG) TRAFFIC_COUNTERS_DUMP = ( 'Chain OUTPUT (policy ACCEPT 400 packets, 65901 bytes)\n' ' pkts bytes target prot opt in out source' ' destination \n' ' 400 65901 chain1 all -- * * 0.0.0.0/0' ' 0.0.0.0/0 \n' ' 400 65901 chain2 all -- * * 0.0.0.0/0' ' 0.0.0.0/0 \n') FILTER_RESTORE_DUMP = ('# Generated by iptables_manager\n' '*filter\n' ':FORWARD - [0:0]\n' ':INPUT - [0:0]\n' ':OUTPUT - [0:0]\n' ':neutron-filter-top - [0:0]\n' ':%(bn)s-FORWARD - [0:0]\n' ':%(bn)s-INPUT - [0:0]\n' ':%(bn)s-OUTPUT - [0:0]\n' ':%(bn)s-test-filter - [0:0]\n' ':%(bn)s-local - [0:0]\n' '-A FORWARD -j neutron-filter-top\n' '-A FORWARD -j %(bn)s-FORWARD\n' '-A INPUT -j %(bn)s-INPUT\n' '-A OUTPUT -j neutron-filter-top\n' '-A OUTPUT -j %(bn)s-OUTPUT\n' '-A neutron-filter-top -j %(bn)s-local\n' '%(filter_rules)s' 'COMMIT\n' '# Completed by iptables_manager\n') NAT_RESTORE_TEMPLATE = ('# Generated by iptables_manager\n' '*nat\n' ':OUTPUT - [0:0]\n' ':POSTROUTING - [0:0]\n' ':PREROUTING - [0:0]\n' ':neutron-postrouting-bottom - [0:0]\n' ':%(bn)s-OUTPUT - [0:0]\n' ':%(bn)s-POSTROUTING - [0:0]\n' ':%(bn)s-PREROUTING - [0:0]\n' ':%(bn)s-float-snat - [0:0]\n' ':%(bn)s-snat - [0:0]\n' '-A OUTPUT -j %(bn)s-OUTPUT\n' '-A POSTROUTING -j %(bn)s-POSTROUTING\n' '-A POSTROUTING -j neutron-postrouting-bottom\n' '-A PREROUTING -j %(bn)s-PREROUTING\n' '-A neutron-postrouting-bottom -j %(bn)s-snat\n' '-A %(bn)s-snat -j ' '%(bn)s-float-snat\n' 'COMMIT\n' '# Completed by iptables_manager\n') NAT_RESTORE_DUMP = NAT_RESTORE_TEMPLATE % IPTABLES_ARG class IptablesTestCase(base.BaseTestCase): def test_get_binary_name_in_unittest(self): # Corresponds to sys.argv content when running python -m unittest class with mock.patch('sys.argv', ['python -m unittest', 'class']): binary_name = iptables_manager.get_binary_name() self.assertEqual('python_-m_unitte', binary_name) class IptablesCommentsTestCase(base.BaseTestCase): def setUp(self): super(IptablesCommentsTestCase, self).setUp() cfg.CONF.set_override('comment_iptables_rules', True, 'AGENT') self.iptables = iptables_manager.IptablesManager() self.execute = mock.patch.object(self.iptables, "execute").start() def test_comments_short_enough(self): for attr in dir(ic): if not attr.startswith('__') and len(getattr(ic, attr)) > 255: self.fail("Iptables comment %s is longer than 255 characters." % attr) def test_reordering_of_jump_rule_comments(self): # jump at the start self.assertEqual( '-m comment --comment "aloha" -j sg-chain', iptables_manager.comment_rule('-j sg-chain', 'aloha')) # jump in the middle self.assertEqual( '-s source -m comment --comment "aloha" -j sg-chain', iptables_manager.comment_rule('-s source -j sg-chain', 'aloha')) # no jump rule self.assertEqual( '-s source -m comment --comment "aloha"', iptables_manager.comment_rule('-s source', 'aloha')) def test_add_filter_rule(self): iptables_args = {} iptables_args.update(IPTABLES_ARG) filter_rules = ('-I %(bn)s-INPUT 1 -s 0/0 -d 192.168.0.2 -j ' '%(bn)s-filter\n-I %(bn)s-filter 1 -j DROP\n' % iptables_args) iptables_args['filter_rules'] = filter_rules filter_dump_mod = FILTER_WITH_RULES_TEMPLATE % iptables_args raw_dump = _generate_raw_dump(IPTABLES_ARG) mangle_dump = _generate_mangle_dump(IPTABLES_ARG) expected_calls_and_values = [ (mock.call(['iptables-save'], run_as_root=True), ''), (mock.call(['iptables-restore', '-n'], process_input=(filter_dump_mod + mangle_dump + COMMENTED_NAT_DUMP + raw_dump), run_as_root=True, log_fail_as_error=False), None), (mock.call(['iptables-save'], run_as_root=True), ''), (mock.call(['iptables-restore', '-n'], process_input=(FILTER_DUMP + mangle_dump + COMMENTED_NAT_DUMP + raw_dump), run_as_root=True, log_fail_as_error=False), None), ] tools.setup_mock_calls(self.execute, expected_calls_and_values) self.iptables.ipv4['filter'].add_chain('filter') self.iptables.ipv4['filter'].add_rule('filter', '-j DROP') self.iptables.ipv4['filter'].add_rule('INPUT', '-s 0/0 -d 192.168.0.2 -j' ' %(bn)s-filter' % IPTABLES_ARG) self.iptables.apply() self.iptables.ipv4['filter'].remove_rule('filter', '-j DROP') self.iptables.ipv4['filter'].remove_rule('INPUT', '-s 0/0 -d 192.168.0.2 -j' ' %(bn)s-filter' % IPTABLES_ARG) self.iptables.ipv4['filter'].remove_chain('filter') self.iptables.apply() tools.verify_mock_calls(self.execute, expected_calls_and_values) def _generate_mangle_dump(iptables_args): return ('# Generated by iptables_manager\n' '*mangle\n' ':FORWARD - [0:0]\n' ':INPUT - [0:0]\n' ':OUTPUT - [0:0]\n' ':POSTROUTING - [0:0]\n' ':PREROUTING - [0:0]\n' ':%(bn)s-FORWARD - [0:0]\n' ':%(bn)s-INPUT - [0:0]\n' ':%(bn)s-OUTPUT - [0:0]\n' ':%(bn)s-POSTROUTING - [0:0]\n' ':%(bn)s-PREROUTING - [0:0]\n' ':%(bn)s-mark - [0:0]\n' '-I FORWARD 1 -j %(bn)s-FORWARD\n' '-I INPUT 1 -j %(bn)s-INPUT\n' '-I OUTPUT 1 -j %(bn)s-OUTPUT\n' '-I POSTROUTING 1 -j %(bn)s-POSTROUTING\n' '-I PREROUTING 1 -j %(bn)s-PREROUTING\n' '-I %(bn)s-PREROUTING 1 -j %(bn)s-mark\n' 'COMMIT\n' '# Completed by iptables_manager\n' % iptables_args) def _generate_mangle_dump_v6(iptables_args): return ('# Generated by iptables_manager\n' '*mangle\n' ':FORWARD - [0:0]\n' ':INPUT - [0:0]\n' ':OUTPUT - [0:0]\n' ':POSTROUTING - [0:0]\n' ':PREROUTING - [0:0]\n' ':%(bn)s-FORWARD - [0:0]\n' ':%(bn)s-INPUT - [0:0]\n' ':%(bn)s-OUTPUT - [0:0]\n' ':%(bn)s-POSTROUTING - [0:0]\n' ':%(bn)s-PREROUTING - [0:0]\n' '-I FORWARD 1 -j %(bn)s-FORWARD\n' '-I INPUT 1 -j %(bn)s-INPUT\n' '-I OUTPUT 1 -j %(bn)s-OUTPUT\n' '-I POSTROUTING 1 -j %(bn)s-POSTROUTING\n' '-I PREROUTING 1 -j %(bn)s-PREROUTING\n' 'COMMIT\n' '# Completed by iptables_manager\n' % iptables_args) def _generate_raw_dump(iptables_args): return ('# Generated by iptables_manager\n' '*raw\n' ':OUTPUT - [0:0]\n' ':PREROUTING - [0:0]\n' ':%(bn)s-OUTPUT - [0:0]\n' ':%(bn)s-PREROUTING - [0:0]\n' '-I OUTPUT 1 -j %(bn)s-OUTPUT\n' '-I PREROUTING 1 -j %(bn)s-PREROUTING\n' 'COMMIT\n' '# Completed by iptables_manager\n' % iptables_args) def _generate_mangle_restore_dump(iptables_args): return ('# Generated by iptables_manager\n' '*mangle\n' ':FORWARD - [0:0]\n' ':INPUT - [0:0]\n' ':OUTPUT - [0:0]\n' ':POSTROUTING - [0:0]\n' ':PREROUTING - [0:0]\n' ':%(bn)s-FORWARD - [0:0]\n' ':%(bn)s-INPUT - [0:0]\n' ':%(bn)s-OUTPUT - [0:0]\n' ':%(bn)s-POSTROUTING - [0:0]\n' ':%(bn)s-PREROUTING - [0:0]\n' ':%(bn)s-mark - [0:0]\n' '-A FORWARD -j %(bn)s-FORWARD\n' '-A INPUT -j %(bn)s-INPUT\n' '-A OUTPUT -j %(bn)s-OUTPUT\n' '-A POSTROUTING -j %(bn)s-POSTROUTING\n' '-A PREROUTING -j %(bn)s-PREROUTING\n' '-A %(bn)s-PREROUTING -j %(bn)s-mark\n' 'COMMIT\n' '# Completed by iptables_manager\n' % iptables_args) def _generate_raw_restore_dump(iptables_args): return ('# Generated by iptables_manager\n' '*raw\n' ':OUTPUT - [0:0]\n' ':PREROUTING - [0:0]\n' ':%(bn)s-OUTPUT - [0:0]\n' ':%(bn)s-PREROUTING - [0:0]\n' '-A OUTPUT -j %(bn)s-OUTPUT\n' '-A PREROUTING -j %(bn)s-PREROUTING\n' 'COMMIT\n' '# Completed by iptables_manager\n' % iptables_args) MANGLE_DUMP = _generate_mangle_dump(IPTABLES_ARG) MANGLE_DUMP_V6 = _generate_mangle_dump_v6(IPTABLES_ARG) RAW_DUMP = _generate_raw_dump(IPTABLES_ARG) MANGLE_RESTORE_DUMP = _generate_mangle_restore_dump(IPTABLES_ARG) RAW_RESTORE_DUMP = _generate_raw_restore_dump(IPTABLES_ARG) class IptablesFixture(fixtures.Fixture): def _setUp(self): # We MUST save and restore use_table_lock because it is a class # attribute and could change state in some tests, which can cause # the other iptables_manager test cases to randomly fail due to # race conditions. self.use_table_lock = iptables_manager.IptablesManager.use_table_lock iptables_manager.IptablesManager.use_table_lock = False self.addCleanup(self._reset) def _reset(self): iptables_manager.IptablesManager.use_table_lock = self.use_table_lock class IptablesManagerStateFulTestCase(base.BaseTestCase): def setUp(self): super(IptablesManagerStateFulTestCase, self).setUp() cfg.CONF.set_override('comment_iptables_rules', False, 'AGENT') cfg.CONF.set_override('report_interval', 30, 'AGENT') self.execute = mock.patch.object(linux_utils, "execute").start() self.iptables = iptables_manager.IptablesManager() self.useFixture(IptablesFixture()) def test_binary_name(self): expected = os.path.basename(sys.argv[0])[:16] self.assertEqual(expected, iptables_manager.binary_name) def test_get_chain_name(self): name = '0123456789' * 5 # 28 chars is the maximum length of iptables chain name. self.assertEqual(iptables_manager.get_chain_name(name, wrap=False), name[:28]) # 11 chars is the maximum length of chain name of iptable_manager # if binary_name is prepended. self.assertEqual(iptables_manager.get_chain_name(name, wrap=True), name[:11]) def test_defer_apply_with_exception(self): self.iptables._apply = mock.Mock(side_effect=Exception) with testtools.ExpectedException(n_exc.IpTablesApplyException): with self.iptables.defer_apply(): pass def _extend_with_ip6tables_filter(self, expected_calls, filter_dump): expected_calls.insert(2, ( mock.call(['ip6tables-save'], run_as_root=True), '')) expected_calls.insert(3, ( mock.call(['ip6tables-restore', '-n'], process_input=filter_dump, run_as_root=True, log_fail_as_error=False), None)) expected_calls.extend([ (mock.call(['ip6tables-save'], run_as_root=True), ''), (mock.call(['ip6tables-restore', '-n'], process_input=filter_dump, run_as_root=True, log_fail_as_error=False), None)]) def _test_add_and_remove_chain_custom_binary_name_helper(self, use_ipv6): bn = ("xbcdef" * 5) self.iptables = iptables_manager.IptablesManager( binary_name=bn, use_ipv6=use_ipv6) self.execute = mock.patch.object(self.iptables, "execute").start() iptables_args = {'bn': bn[:16], 'filter_rules': ''} filter_dump = FILTER_WITH_RULES_TEMPLATE % iptables_args filter_dump_ipv6 = FILTER_TEMPLATE % iptables_args filter_dump_mod = filter_dump nat_dump = NAT_TEMPLATE % iptables_args raw_dump = _generate_raw_dump(iptables_args) mangle_dump = _generate_mangle_dump(iptables_args) expected_calls_and_values = [ (mock.call(['iptables-save'], run_as_root=True), ''), (mock.call(['iptables-restore', '-n'], process_input=(filter_dump_mod + mangle_dump + nat_dump + raw_dump), run_as_root=True, log_fail_as_error=False), None), (mock.call(['iptables-save'], run_as_root=True), ''), (mock.call(['iptables-restore', '-n'], process_input=(filter_dump + mangle_dump + nat_dump + raw_dump), run_as_root=True, log_fail_as_error=False), None), ] if use_ipv6: mangle_dump_v6 = _generate_mangle_dump_v6(iptables_args) self._extend_with_ip6tables_filter( expected_calls_and_values, filter_dump_ipv6 + mangle_dump_v6 + raw_dump) tools.setup_mock_calls(self.execute, expected_calls_and_values) self.iptables.ipv4['filter'].add_chain('filter') self.iptables.apply() self.iptables.ipv4['filter'].empty_chain('filter') self.iptables.apply() tools.verify_mock_calls(self.execute, expected_calls_and_values) def test_add_and_remove_chain_custom_binary_name(self): self._test_add_and_remove_chain_custom_binary_name_helper(False) def test_add_and_remove_chain_custom_binary_name_with_ipv6(self): self._test_add_and_remove_chain_custom_binary_name_helper(True) def _test_empty_chain_custom_binary_name_helper(self, use_ipv6): bn = ("xbcdef" * 5)[:16] self.iptables = iptables_manager.IptablesManager( binary_name=bn, use_ipv6=use_ipv6) self.execute = mock.patch.object(self.iptables, "execute").start() iptables_args = {'bn': bn} filter_dump = FILTER_TEMPLATE % iptables_args filter_rules = ('-I %(bn)s-filter 1 -s 0/0 -d 192.168.0.2\n' % iptables_args) iptables_args['filter_rules'] = filter_rules filter_dump_mod = FILTER_WITH_RULES_TEMPLATE % iptables_args nat_dump = NAT_TEMPLATE % iptables_args raw_dump = _generate_raw_dump(iptables_args) mangle_dump = _generate_mangle_dump(iptables_args) expected_calls_and_values = [ (mock.call(['iptables-save'], run_as_root=True), ''), (mock.call(['iptables-restore', '-n'], process_input=(filter_dump_mod + mangle_dump + nat_dump + raw_dump), run_as_root=True, log_fail_as_error=False), None), (mock.call(['iptables-save'], run_as_root=True), ''), (mock.call(['iptables-restore', '-n'], process_input=(filter_dump + mangle_dump + nat_dump + raw_dump), run_as_root=True, log_fail_as_error=False), None), ] if use_ipv6: mangle_dump_v6 = _generate_mangle_dump_v6(iptables_args) self._extend_with_ip6tables_filter( expected_calls_and_values, filter_dump + mangle_dump_v6 + raw_dump) tools.setup_mock_calls(self.execute, expected_calls_and_values) self.iptables.ipv4['filter'].add_chain('filter') self.iptables.ipv4['filter'].add_rule('filter', '-s 0/0 -d 192.168.0.2') self.iptables.apply() self.iptables.ipv4['filter'].remove_chain('filter') self.iptables.apply() tools.verify_mock_calls(self.execute, expected_calls_and_values) def test_empty_chain_custom_binary_name(self): self._test_empty_chain_custom_binary_name_helper(False) def test_empty_chain_custom_binary_name_with_ipv6(self): self._test_empty_chain_custom_binary_name_helper(True) def _test_add_and_remove_chain_helper(self, use_ipv6): self.iptables = iptables_manager.IptablesManager( use_ipv6=use_ipv6) self.execute = mock.patch.object(self.iptables, "execute").start() filter_dump_mod = FILTER_WITH_RULES_TEMPLATE % IPTABLES_ARG expected_calls_and_values = [ (mock.call(['iptables-save'], run_as_root=True), ''), (mock.call(['iptables-restore', '-n'], process_input=(filter_dump_mod + MANGLE_DUMP + NAT_DUMP + RAW_DUMP), run_as_root=True, log_fail_as_error=False), None), (mock.call(['iptables-save'], run_as_root=True), ''), (mock.call(['iptables-restore', '-n'], process_input=(FILTER_DUMP + MANGLE_DUMP + NAT_DUMP + RAW_DUMP), run_as_root=True, log_fail_as_error=False), None), ] if use_ipv6: self._extend_with_ip6tables_filter( expected_calls_and_values, FILTER_DUMP + MANGLE_DUMP_V6 + RAW_DUMP) tools.setup_mock_calls(self.execute, expected_calls_and_values) self.iptables.ipv4['filter'].add_chain('filter') self.iptables.apply() self.iptables.ipv4['filter'].remove_chain('filter') self.iptables.apply() tools.verify_mock_calls(self.execute, expected_calls_and_values) def test_add_and_remove_chain(self): self._test_add_and_remove_chain_helper(False) def test_add_and_remove_chain_with_ipv6(self): self._test_add_and_remove_chain_helper(True) def _test_add_filter_rule_helper(self, use_ipv6): self.iptables = iptables_manager.IptablesManager( use_ipv6=use_ipv6) self.execute = mock.patch.object(self.iptables, "execute").start() iptables_args = {} iptables_args.update(IPTABLES_ARG) filter_rules = ('-I %(bn)s-INPUT 1 -s 0/0 -d 192.168.0.2 -j ' '%(bn)s-filter\n-I %(bn)s-filter 1 -j DROP\n' % iptables_args) iptables_args['filter_rules'] = filter_rules filter_dump_mod = FILTER_WITH_RULES_TEMPLATE % iptables_args raw_dump = RAW_DUMP % IPTABLES_ARG expected_calls_and_values = [ (mock.call(['iptables-save'], run_as_root=True), ''), (mock.call(['iptables-restore', '-n'], process_input=(filter_dump_mod + MANGLE_DUMP + NAT_DUMP + RAW_DUMP), run_as_root=True, log_fail_as_error=False), None), (mock.call(['iptables-save'], run_as_root=True), ''), (mock.call(['iptables-restore', '-n'], process_input=(FILTER_DUMP + MANGLE_DUMP + NAT_DUMP + RAW_DUMP), run_as_root=True, log_fail_as_error=False), None), ] if use_ipv6: self._extend_with_ip6tables_filter( expected_calls_and_values, FILTER_DUMP + MANGLE_DUMP_V6 + raw_dump) tools.setup_mock_calls(self.execute, expected_calls_and_values) self.iptables.ipv4['filter'].add_chain('filter') self.iptables.ipv4['filter'].add_rule('filter', '-j DROP') self.iptables.ipv4['filter'].add_rule('INPUT', '-s 0/0 -d 192.168.0.2 -j' ' %(bn)s-filter' % IPTABLES_ARG) self.iptables.apply() self.iptables.ipv4['filter'].remove_rule('filter', '-j DROP') self.iptables.ipv4['filter'].remove_rule('INPUT', '-s 0/0 -d 192.168.0.2 -j' ' %(bn)s-filter' % IPTABLES_ARG) self.iptables.ipv4['filter'].remove_chain('filter') self.iptables.apply() tools.verify_mock_calls(self.execute, expected_calls_and_values) def test_add_filter_rule(self): self._test_add_filter_rule_helper(False) def test_add_filter_rule_with_ipv6(self): self._test_add_filter_rule_helper(True) def _test_rule_with_wrap_target_helper(self, use_ipv6): self.iptables = iptables_manager.IptablesManager( use_ipv6=use_ipv6) self.execute = mock.patch.object(self.iptables, "execute").start() name = '0123456789' * 5 wrap = "%s-%s" % (iptables_manager.binary_name, iptables_manager.get_chain_name(name)) iptables_args = {'bn': iptables_manager.binary_name, 'wrap': wrap} filter_dump_mod = ('# Generated by iptables_manager\n' '*filter\n' ':FORWARD - [0:0]\n' ':INPUT - [0:0]\n' ':OUTPUT - [0:0]\n' ':neutron-filter-top - [0:0]\n' ':%(wrap)s - [0:0]\n' ':%(bn)s-FORWARD - [0:0]\n' ':%(bn)s-INPUT - [0:0]\n' ':%(bn)s-OUTPUT - [0:0]\n' ':%(bn)s-local - [0:0]\n' '-I FORWARD 1 -j neutron-filter-top\n' '-I FORWARD 2 -j %(bn)s-FORWARD\n' '-I INPUT 1 -j %(bn)s-INPUT\n' '-I OUTPUT 1 -j neutron-filter-top\n' '-I OUTPUT 2 -j %(bn)s-OUTPUT\n' '-I neutron-filter-top 1 -j %(bn)s-local\n' '-I %(bn)s-INPUT 1 -s 0/0 -d 192.168.0.2 -j ' '%(wrap)s\n' 'COMMIT\n' '# Completed by iptables_manager\n' % iptables_args) raw_dump = RAW_DUMP % IPTABLES_ARG expected_calls_and_values = [ (mock.call(['iptables-save'], run_as_root=True), ''), (mock.call(['iptables-restore', '-n'], process_input=(filter_dump_mod + MANGLE_DUMP + NAT_DUMP + RAW_DUMP), run_as_root=True, log_fail_as_error=False), None), (mock.call(['iptables-save'], run_as_root=True), ''), (mock.call(['iptables-restore', '-n'], process_input=(FILTER_DUMP + MANGLE_DUMP + NAT_DUMP + RAW_DUMP), run_as_root=True, log_fail_as_error=False), None), ] if use_ipv6: self._extend_with_ip6tables_filter( expected_calls_and_values, FILTER_DUMP + MANGLE_DUMP_V6 + raw_dump) tools.setup_mock_calls(self.execute, expected_calls_and_values) self.iptables.ipv4['filter'].add_chain(name) self.iptables.ipv4['filter'].add_rule('INPUT', '-s 0/0 -d 192.168.0.2 -j' ' $%s' % name) self.iptables.apply() self.iptables.ipv4['filter'].remove_rule('INPUT', '-s 0/0 -d 192.168.0.2 -j' ' $%s' % name) self.iptables.ipv4['filter'].remove_chain(name) self.iptables.apply() tools.verify_mock_calls(self.execute, expected_calls_and_values) def test_rule_with_wrap_target(self): self._test_rule_with_wrap_target_helper(False) def test_rule_with_wrap_target_with_ipv6(self): self._test_rule_with_wrap_target_helper(True) def _test_add_mangle_rule_helper(self, use_ipv6): self.iptables = iptables_manager.IptablesManager( use_ipv6=use_ipv6) self.execute = mock.patch.object(self.iptables, "execute").start() mangle_dump_mod = ( '# Generated by iptables_manager\n' '*mangle\n' ':FORWARD - [0:0]\n' ':INPUT - [0:0]\n' ':OUTPUT - [0:0]\n' ':POSTROUTING - [0:0]\n' ':PREROUTING - [0:0]\n' ':%(bn)s-FORWARD - [0:0]\n' ':%(bn)s-INPUT - [0:0]\n' ':%(bn)s-OUTPUT - [0:0]\n' ':%(bn)s-POSTROUTING - [0:0]\n' ':%(bn)s-PREROUTING - [0:0]\n' ':%(bn)s-mangle - [0:0]\n' ':%(bn)s-mark - [0:0]\n' '-I FORWARD 1 -j %(bn)s-FORWARD\n' '-I INPUT 1 -j %(bn)s-INPUT\n' '-I OUTPUT 1 -j %(bn)s-OUTPUT\n' '-I POSTROUTING 1 -j %(bn)s-POSTROUTING\n' '-I PREROUTING 1 -j %(bn)s-PREROUTING\n' '-I %(bn)s-PREROUTING 1 -j %(bn)s-mark\n' '-I %(bn)s-PREROUTING 2 -j MARK --set-xmark 0x1/%(mark)s\n' 'COMMIT\n' '# Completed by iptables_manager\n' % IPTABLES_ARG) expected_calls_and_values = [ (mock.call(['iptables-save'], run_as_root=True), ''), (mock.call(['iptables-restore', '-n'], process_input=(FILTER_DUMP + mangle_dump_mod + NAT_DUMP + RAW_DUMP), run_as_root=True, log_fail_as_error=False), None), (mock.call(['iptables-save'], run_as_root=True), ''), (mock.call(['iptables-restore', '-n'], process_input=(FILTER_DUMP + MANGLE_DUMP + NAT_DUMP + RAW_DUMP), run_as_root=True, log_fail_as_error=False), None), ] if use_ipv6: self._extend_with_ip6tables_filter( expected_calls_and_values, FILTER_DUMP + MANGLE_DUMP_V6 + RAW_DUMP) tools.setup_mock_calls(self.execute, expected_calls_and_values) self.iptables.ipv4['mangle'].add_chain('mangle') self.iptables.ipv4['mangle'].add_rule( 'PREROUTING', '-j MARK --set-xmark 0x1/%s' % constants.ROUTER_MARK_MASK) self.iptables.apply() self.iptables.ipv4['mangle'].remove_rule( 'PREROUTING', '-j MARK --set-xmark 0x1/%s' % constants.ROUTER_MARK_MASK) self.iptables.ipv4['mangle'].remove_chain('mangle') self.iptables.apply() tools.verify_mock_calls(self.execute, expected_calls_and_values) def test_add_mangle_rule(self): self._test_add_mangle_rule_helper(False) def test_add_mangle_rule_with_ipv6(self): self._test_add_mangle_rule_helper(True) def _test_add_nat_rule_helper(self, use_ipv6): self.iptables = iptables_manager.IptablesManager( use_ipv6=use_ipv6) self.execute = mock.patch.object(self.iptables, "execute").start() nat_dump = NAT_TEMPLATE % IPTABLES_ARG nat_dump_mod = ('# Generated by iptables_manager\n' '*nat\n' ':OUTPUT - [0:0]\n' ':POSTROUTING - [0:0]\n' ':PREROUTING - [0:0]\n' ':neutron-postrouting-bottom - [0:0]\n' ':%(bn)s-OUTPUT - [0:0]\n' ':%(bn)s-POSTROUTING - [0:0]\n' ':%(bn)s-PREROUTING - [0:0]\n' ':%(bn)s-float-snat - [0:0]\n' ':%(bn)s-nat - [0:0]\n' ':%(bn)s-snat - [0:0]\n' '-I OUTPUT 1 -j %(bn)s-OUTPUT\n' '-I POSTROUTING 1 -j %(bn)s-POSTROUTING\n' '-I POSTROUTING 2 -j neutron-postrouting-bottom\n' '-I PREROUTING 1 -j %(bn)s-PREROUTING\n' '-I neutron-postrouting-bottom 1 -j %(bn)s-snat\n' '-I %(bn)s-PREROUTING 1 -d 192.168.0.3 -j ' '%(bn)s-nat\n' '-I %(bn)s-nat 1 -p tcp --dport 8080 -j ' 'REDIRECT --to-port 80\n' '-I %(bn)s-snat 1 -j %(bn)s-float-snat\n' 'COMMIT\n' '# Completed by iptables_manager\n' % IPTABLES_ARG) raw_dump = RAW_DUMP % IPTABLES_ARG expected_calls_and_values = [ (mock.call(['iptables-save'], run_as_root=True), ''), (mock.call(['iptables-restore', '-n'], process_input=(FILTER_DUMP + MANGLE_DUMP + nat_dump_mod + RAW_DUMP), run_as_root=True, log_fail_as_error=False), None), (mock.call(['iptables-save'], run_as_root=True), ''), (mock.call(['iptables-restore', '-n'], process_input=(FILTER_DUMP + MANGLE_DUMP + nat_dump + RAW_DUMP), run_as_root=True, log_fail_as_error=False), None), ] if use_ipv6: self._extend_with_ip6tables_filter( expected_calls_and_values, FILTER_DUMP + MANGLE_DUMP_V6 + raw_dump) tools.setup_mock_calls(self.execute, expected_calls_and_values) self.iptables.ipv4['nat'].add_chain('nat') self.iptables.ipv4['nat'].add_rule('PREROUTING', '-d 192.168.0.3 -j ' '%(bn)s-nat' % IPTABLES_ARG) self.iptables.ipv4['nat'].add_rule('nat', '-p tcp --dport 8080' + ' -j REDIRECT --to-port 80') self.iptables.apply() self.iptables.ipv4['nat'].remove_rule('nat', '-p tcp --dport 8080 -j' ' REDIRECT --to-port 80') self.iptables.ipv4['nat'].remove_rule('PREROUTING', '-d 192.168.0.3 -j ' '%(bn)s-nat' % IPTABLES_ARG) self.iptables.ipv4['nat'].remove_chain('nat') self.iptables.apply() tools.verify_mock_calls(self.execute, expected_calls_and_values) def test_add_nat_rule(self): self._test_add_nat_rule_helper(False) def test_add_nat_rule_with_ipv6(self): self._test_add_nat_rule_helper(True) def _test_add_raw_rule_helper(self, use_ipv6): self.iptables = iptables_manager.IptablesManager( use_ipv6=use_ipv6) self.execute = mock.patch.object(self.iptables, "execute").start() raw_dump_mod = ('# Generated by iptables_manager\n' '*raw\n' ':OUTPUT - [0:0]\n' ':PREROUTING - [0:0]\n' ':%(bn)s-OUTPUT - [0:0]\n' ':%(bn)s-PREROUTING - [0:0]\n' ':%(bn)s-raw - [0:0]\n' '-I OUTPUT 1 -j %(bn)s-OUTPUT\n' '-I PREROUTING 1 -j %(bn)s-PREROUTING\n' '-I %(bn)s-PREROUTING 1 -j CT --notrack\n' 'COMMIT\n' '# Completed by iptables_manager\n' % IPTABLES_ARG) expected_calls_and_values = [ (mock.call(['iptables-save'], run_as_root=True), ''), (mock.call(['iptables-restore', '-n'], process_input=(FILTER_DUMP + MANGLE_DUMP + NAT_DUMP + raw_dump_mod), run_as_root=True, log_fail_as_error=False), None), (mock.call(['iptables-save'], run_as_root=True), ''), (mock.call(['iptables-restore', '-n'], process_input=(FILTER_DUMP + MANGLE_DUMP + NAT_DUMP + RAW_DUMP), run_as_root=True, log_fail_as_error=False), None), ] if use_ipv6: self._extend_with_ip6tables_filter( expected_calls_and_values, FILTER_DUMP + MANGLE_DUMP_V6 + RAW_DUMP) tools.setup_mock_calls(self.execute, expected_calls_and_values) self.iptables.ipv4['raw'].add_chain('raw') self.iptables.ipv4['raw'].add_rule('PREROUTING', '-j CT --notrack') self.iptables.apply() self.iptables.ipv4['raw'].remove_rule('PREROUTING', '-j CT --notrack') self.iptables.ipv4['raw'].remove_chain('raw') self.iptables.apply() tools.verify_mock_calls(self.execute, expected_calls_and_values) def test_add_raw_rule(self): self._test_add_raw_rule_helper(False) def test_add_raw_rule_with_ipv6(self): self._test_add_raw_rule_helper(True) def test_add_rule_to_a_nonexistent_chain(self): self.assertRaises(LookupError, self.iptables.ipv4['filter'].add_rule, 'nonexistent', '-j DROP') def test_remove_nonexistent_chain(self): with mock.patch.object(iptables_manager, "LOG") as log: self.iptables.ipv4['filter'].remove_chain('nonexistent') log.debug.assert_called_once_with( 'Attempted to remove chain %s which does not exist', 'nonexistent') def test_remove_nonexistent_rule(self): with mock.patch.object(iptables_manager, "LOG") as log: self.iptables.ipv4['filter'].remove_rule('nonexistent', '-j DROP') log.warning.assert_called_once_with( 'Tried to remove rule that was not there: ' '%(chain)r %(rule)r %(wrap)r %(top)r', {'wrap': True, 'top': False, 'rule': '-j DROP', 'chain': 'nonexistent'}) def test_iptables__apply_synchronized_no_namespace(self): self.execute.side_effect = RuntimeError # no namespace set so should raise self.assertRaises(RuntimeError, self.iptables._apply_synchronized) self.iptables.namespace = 'test' with mock.patch('neutron.agent.linux.ip_lib.IpNetnsCommand.exists', return_value=True): self.assertRaises(RuntimeError, self.iptables._apply_synchronized) with mock.patch('neutron.agent.linux.ip_lib.IpNetnsCommand.exists', return_value=False): self.assertEqual([], self.iptables._apply_synchronized()) def test_iptables_failure_with_no_failing_line_number(self): with mock.patch.object(iptables_manager, "LOG") as log: # generate Runtime errors on iptables-restore calls def iptables_restore_failer(*args, **kwargs): if 'iptables-restore' in args[0]: self.input_lines = kwargs['process_input'].split('\n') # don't provide a specific failure message so all lines # are logged raise RuntimeError() return FILTER_DUMP self.execute.side_effect = iptables_restore_failer # _apply_synchronized calls iptables-restore so it should raise # a RuntimeError self.assertRaises(RuntimeError, self.iptables._apply_synchronized) # The RuntimeError should have triggered a log of the input to the # process that it failed to execute. Verify by comparing the log # call to the 'process_input' arg given to the failed iptables-restore # call. # Failure without a specific line number in the error should cause # all lines to be logged with numbers. logged = ['%7d. %s' % (n, l) for n, l in enumerate(self.input_lines, 1)] log.error.assert_called_once_with(_( 'IPTablesManager.apply failed to apply the ' 'following set of iptables rules:\n%s'), '\n'.join(logged) ) def test_iptables_failure(self): with mock.patch.object(iptables_manager, "LOG") as log: # generate Runtime errors on iptables-restore calls def iptables_restore_failer(*args, **kwargs): if 'iptables-restore' in args[0]: self.input_lines = kwargs['process_input'].split('\n') # pretend line 11 failed msg = ("Exit code: 1\nStdout: ''\n" "Stderr: 'iptables-restore: line 11 failed\n'") raise linux_utils.ProcessExecutionError( msg, iptables_manager.XTABLES_RESOURCE_PROBLEM_CODE) return FILTER_DUMP self.execute.side_effect = iptables_restore_failer # _apply_synchronized calls iptables-restore so it should raise # a RuntimeError self.assertRaises(RuntimeError, self.iptables._apply_synchronized) # check that we tried with -w when the first attempt failed self.execute.assert_has_calls( [mock.call(['iptables-restore', '-n'], process_input=mock.ANY, run_as_root=True, log_fail_as_error=False), mock.call(['iptables-restore', '-n', '-w', '10', '-W', iptables_manager.XLOCK_WAIT_INTERVAL], process_input=mock.ANY, run_as_root=True)]) # The RuntimeError should have triggered a log of the input to the # process that it failed to execute. Verify by comparing the log # call to the 'process_input' arg given to the failed iptables-restore # call. # Line 11 of the input was marked as failing so lines (11 - context) # to (11 + context) should be logged ctx = iptables_manager.IPTABLES_ERROR_LINES_OF_CONTEXT log_start = max(0, 11 - ctx) log_end = 11 + ctx logged = ['%7d. %s' % (n, l) for n, l in enumerate(self.input_lines[log_start:log_end], log_start + 1)] log.error.assert_called_once_with(_( 'IPTablesManager.apply failed to apply the ' 'following set of iptables rules:\n%s'), '\n'.join(logged) ) def test_iptables_use_table_lock(self): # Under normal operation, if we do call iptables-restore with a -w # and it succeeds, the next call will only use -w. PE_error = linux_utils.ProcessExecutionError( "", iptables_manager.XTABLES_RESOURCE_PROBLEM_CODE) self.execute.side_effect = [FILTER_DUMP, PE_error, None, FILTER_DUMP, None, FILTER_DUMP, None] self.iptables._apply_synchronized() self.assertEqual(3, self.execute.call_count) self.execute.assert_has_calls( [mock.call(['iptables-save'], run_as_root=True), mock.call(['iptables-restore', '-n'], process_input=mock.ANY, run_as_root=True, log_fail_as_error=False), mock.call(['iptables-restore', '-n', '-w', '10', '-W', iptables_manager.XLOCK_WAIT_INTERVAL], process_input=mock.ANY, run_as_root=True)]) self.execute.reset_mock() self.iptables._apply_synchronized() self.assertEqual(2, self.execute.call_count) self.execute.assert_has_calls( [mock.call(['iptables-save'], run_as_root=True), mock.call(['iptables-restore', '-n', '-w', '10', '-W', iptables_manager.XLOCK_WAIT_INTERVAL], process_input=mock.ANY, run_as_root=True)]) # Another instance of the class should behave similarly now self.execute.reset_mock() iptm = iptables_manager.IptablesManager() iptm._apply_synchronized() self.assertEqual(2, self.execute.call_count) self.execute.assert_has_calls( [mock.call(['iptables-save'], run_as_root=True), mock.call(['iptables-restore', '-n', '-w', '10', '-W', iptables_manager.XLOCK_WAIT_INTERVAL], process_input=mock.ANY, run_as_root=True)]) def test_get_traffic_counters_chain_notexists(self): with mock.patch.object(iptables_manager, "LOG") as log: acc = self.iptables.get_traffic_counters('chain1') self.assertIsNone(acc) self.assertEqual(0, self.execute.call_count) log.warning.assert_called_once_with( 'Attempted to get traffic counters of chain %s which ' 'does not exist', 'chain1') def _test_get_traffic_counters_helper(self, use_ipv6): self.iptables = iptables_manager.IptablesManager( use_ipv6=use_ipv6) self.execute = mock.patch.object(self.iptables, "execute").start() exp_packets = 800 exp_bytes = 131802 expected_calls_and_values = [ (mock.call(['iptables', '-t', 'filter', '-L', 'OUTPUT', '-n', '-v', '-x', '-w', '10'], run_as_root=True), TRAFFIC_COUNTERS_DUMP), (mock.call(['iptables', '-t', 'raw', '-L', 'OUTPUT', '-n', '-v', '-x', '-w', '10'], run_as_root=True), ''), (mock.call(['iptables', '-t', 'mangle', '-L', 'OUTPUT', '-n', '-v', '-x', '-w', '10'], run_as_root=True), ''), (mock.call(['iptables', '-t', 'nat', '-L', 'OUTPUT', '-n', '-v', '-x', '-w', '10'], run_as_root=True), ''), ] if use_ipv6: expected_calls_and_values.append( (mock.call(['ip6tables', '-t', 'raw', '-L', 'OUTPUT', '-n', '-v', '-x', '-w', '10'], run_as_root=True), '')) expected_calls_and_values.append( (mock.call(['ip6tables', '-t', 'filter', '-L', 'OUTPUT', '-n', '-v', '-x', '-w', '10'], run_as_root=True), TRAFFIC_COUNTERS_DUMP)) expected_calls_and_values.append( (mock.call(['ip6tables', '-t', 'mangle', '-L', 'OUTPUT', '-n', '-v', '-x', '-w', '10'], run_as_root=True), '')) exp_packets *= 2 exp_bytes *= 2 tools.setup_mock_calls(self.execute, expected_calls_and_values) acc = self.iptables.get_traffic_counters('OUTPUT') self.assertEqual(acc['pkts'], exp_packets) self.assertEqual(acc['bytes'], exp_bytes) tools.verify_mock_calls(self.execute, expected_calls_and_values, any_order=True) def test_get_traffic_counters(self): self._test_get_traffic_counters_helper(False) def test_get_traffic_counters_with_ipv6(self): self._test_get_traffic_counters_helper(True) def _test_get_traffic_counters_with_zero_helper(self, use_ipv6): self.iptables = iptables_manager.IptablesManager( use_ipv6=use_ipv6) self.execute = mock.patch.object(self.iptables, "execute").start() exp_packets = 800 exp_bytes = 131802 expected_calls_and_values = [ (mock.call(['iptables', '-t', 'filter', '-L', 'OUTPUT', '-n', '-v', '-x', '-w', '10', '-Z'], run_as_root=True), TRAFFIC_COUNTERS_DUMP), (mock.call(['iptables', '-t', 'raw', '-L', 'OUTPUT', '-n', '-v', '-x', '-w', '10', '-Z'], run_as_root=True), ''), (mock.call(['iptables', '-t', 'mangle', '-L', 'OUTPUT', '-n', '-v', '-x', '-w', '10', '-Z'], run_as_root=True), ''), (mock.call(['iptables', '-t', 'nat', '-L', 'OUTPUT', '-n', '-v', '-x', '-w', '10', '-Z'], run_as_root=True), '') ] if use_ipv6: expected_calls_and_values.append( (mock.call(['ip6tables', '-t', 'raw', '-L', 'OUTPUT', '-n', '-v', '-x', '-w', '10', '-Z'], run_as_root=True), '')) expected_calls_and_values.append( (mock.call(['ip6tables', '-t', 'filter', '-L', 'OUTPUT', '-n', '-v', '-x', '-w', '10', '-Z'], run_as_root=True), TRAFFIC_COUNTERS_DUMP)) expected_calls_and_values.append( (mock.call(['ip6tables', '-t', 'mangle', '-L', 'OUTPUT', '-n', '-v', '-x', '-w', '10', '-Z'], run_as_root=True), '')) exp_packets *= 2 exp_bytes *= 2 tools.setup_mock_calls(self.execute, expected_calls_and_values) acc = self.iptables.get_traffic_counters('OUTPUT', zero=True) self.assertEqual(acc['pkts'], exp_packets) self.assertEqual(acc['bytes'], exp_bytes) tools.verify_mock_calls(self.execute, expected_calls_and_values, any_order=True) def test_get_traffic_counters_with_zero(self): self._test_get_traffic_counters_with_zero_helper(False) def test_get_traffic_counters_with_zero_with_ipv6(self): self._test_get_traffic_counters_with_zero_helper(True) def test_add_blank_rule(self): self.iptables = iptables_manager.IptablesManager( use_ipv6=False) self.execute = mock.patch.object(self.iptables, "execute").start() iptables_args = {} iptables_args.update(IPTABLES_ARG) filter_rules = ('-A %(bn)s-test-filter\n' % iptables_args) iptables_args['filter_rules'] = filter_rules filter_dump_mod = FILTER_RESTORE_DUMP % iptables_args expected_calls_and_values = [ (mock.call(['iptables-save'], run_as_root=True), (filter_dump_mod + MANGLE_RESTORE_DUMP + NAT_RESTORE_DUMP + RAW_RESTORE_DUMP)), ] tools.setup_mock_calls(self.execute, expected_calls_and_values) self.iptables.ipv4['filter'].add_chain('test-filter') self.iptables.ipv4['filter'].add_rule('test-filter', '') self.iptables.apply() tools.verify_mock_calls(self.execute, expected_calls_and_values) def test_add_rule_exchanged_interface_and_ip(self): self.iptables = iptables_manager.IptablesManager( use_ipv6=False) self.execute = mock.patch.object(self.iptables, "execute").start() iptables_args = {} iptables_args.update(IPTABLES_ARG) filter_rules = ('-A %(bn)s-test-filter -d 192.168.0.2 -i tap-xxx ' '-j ACCEPT\n' % iptables_args) iptables_args['filter_rules'] = filter_rules filter_dump_mod = FILTER_RESTORE_DUMP % iptables_args RESTORE_INPUT = ('# Generated by iptables_manager\n' '*filter\n' '-D run.py-test-filter 1\n' '-I run.py-test-filter 1 ' '-i tap-xxx -d 192.168.0.2 -j ACCEPT\n' 'COMMIT\n' '# Completed by iptables_manager\n' % IPTABLES_ARG) expected_calls_and_values = [ (mock.call(['iptables-save'], run_as_root=True), (filter_dump_mod + MANGLE_RESTORE_DUMP + NAT_RESTORE_DUMP + RAW_RESTORE_DUMP)), (mock.call(['iptables-restore', '-n'], process_input=RESTORE_INPUT, run_as_root=True, log_fail_as_error=False), None), ] tools.setup_mock_calls(self.execute, expected_calls_and_values) self.iptables.ipv4['filter'].add_chain('test-filter') self.iptables.ipv4['filter'].add_rule('test-filter', '-i tap-xxx -d 192.168.0.2 ' '-j ACCEPT') self.iptables.apply() tools.verify_mock_calls(self.execute, expected_calls_and_values) class IptablesManagerStateLessTestCase(base.BaseTestCase): def setUp(self): super(IptablesManagerStateLessTestCase, self).setUp() cfg.CONF.set_override('comment_iptables_rules', False, 'AGENT') self.iptables = (iptables_manager.IptablesManager(state_less=True)) def test_nat_not_found(self): self.assertNotIn('nat', self.iptables.ipv4) def test_mangle_not_found(self): self.assertNotIn('mangle', self.iptables.ipv4) def test_initialize_mangle_table(self): iptables = iptables_manager.IptablesManager(state_less=True) iptables.initialize_mangle_table() self.assertIn('mangle', iptables.ipv4) self.assertNotIn('nat', iptables.ipv4) def test_initialize_nat_table(self): iptables = iptables_manager.IptablesManager(state_less=True) iptables.initialize_nat_table() self.assertIn('nat', iptables.ipv4) self.assertNotIn('mangle', iptables.ipv4)