Merge "Support ip6tables for iptables pxe filter"

This commit is contained in:
Zuul 2018-11-27 03:38:12 +00:00 committed by Gerrit Code Review
commit 7e63503ebe
5 changed files with 85 additions and 17 deletions

View File

@ -34,6 +34,12 @@ _OPTS = [
'which are not in desired state are going to be '
'blacklisted based on the list of neighbor MACs '
'on these interfaces.')),
cfg.StrOpt('ip_version',
default='4',
choices=[('4', _('IPv4')),
('6', _('IPv6'))],
help=_('The IP version that will be used for iptables filter. '
'Defaults to 4.')),
]

View File

@ -50,8 +50,18 @@ class IptablesFilter(pxe_filter.BaseFilter):
self.interface = CONF.iptables.dnsmasq_interface
self.chain = CONF.iptables.firewall_chain
self.new_chain = self.chain + '_temp'
# Determine arguments used for pxe filtering, we only support 4 and 6
# at this time.
if CONF.iptables.ip_version == '4':
self._cmd_iptables = 'iptables'
self._dhcp_port = '67'
else:
self._cmd_iptables = 'ip6tables'
self._dhcp_port = '547'
self.base_command = ('sudo', 'ironic-inspector-rootwrap',
CONF.rootwrap_config, 'iptables')
CONF.rootwrap_config, self._cmd_iptables)
def reset(self):
self.enabled = True
@ -137,9 +147,9 @@ class IptablesFilter(pxe_filter.BaseFilter):
# Swap chains
self._iptables('-I', 'INPUT', '-i', self.interface, '-p', 'udp',
'--dport', '67', '-j', chain)
'--dport', self._dhcp_port, '-j', chain)
self._iptables('-D', 'INPUT', '-i', self.interface, '-p', 'udp',
'--dport', '67', '-j', main_chain,
'--dport', self._dhcp_port, '-j', main_chain,
ignore=True)
self._iptables('-F', main_chain, ignore=True)
self._iptables('-X', main_chain, ignore=True)
@ -163,7 +173,7 @@ class IptablesFilter(pxe_filter.BaseFilter):
def _clean_up(self, chain):
self._iptables('-D', 'INPUT', '-i', self.interface, '-p', 'udp',
'--dport', '67', '-j', chain,
'--dport', self._dhcp_port, '-j', chain,
ignore=True)
self._iptables('-F', chain, ignore=True)
self._iptables('-X', chain, ignore=True)

View File

@ -114,20 +114,23 @@ class TestIptablesDriver(test_base.NodeTest):
self.assertRaisesRegex(MyError, 'Oops!', self.driver.init_filter)
self.check_fsm([pxe_filter.Events.initialize, pxe_filter.Events.reset])
def test__iptables_args(self):
def _test__iptables_args(self, expected_port):
self.driver = iptables.IptablesFilter()
self.mock_iptables = self.useFixture(
fixtures.MockPatchObject(self.driver, '_iptables')).mock
self.mock_should_enable_dhcp.return_value = True
_iptables_expected_args = [
('-D', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
'67', '-j', self.driver.new_chain),
expected_port, '-j', self.driver.new_chain),
('-F', self.driver.new_chain),
('-X', self.driver.new_chain),
('-N', self.driver.new_chain),
('-A', self.driver.new_chain, '-j', 'ACCEPT'),
('-I', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
'67', '-j', self.driver.new_chain),
expected_port, '-j', self.driver.new_chain),
('-D', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
'67', '-j', self.driver.chain),
expected_port, '-j', self.driver.chain),
('-F', self.driver.chain),
('-X', self.driver.chain),
('-E', self.driver.new_chain, self.driver.chain)
@ -142,6 +145,14 @@ class TestIptablesDriver(test_base.NodeTest):
self.mock__get_blacklist.assert_called_once_with(self.mock_ironic)
self.check_fsm([pxe_filter.Events.sync])
def test__iptables_args_ipv4(self):
CONF.set_override('ip_version', '4', 'iptables')
self._test__iptables_args('67')
def test__iptables_args_ipv6(self):
CONF.set_override('ip_version', '6', 'iptables')
self._test__iptables_args('547')
def test__iptables_kwargs(self):
_iptables_expected_kwargs = [
{'ignore': True},
@ -163,13 +174,16 @@ class TestIptablesDriver(test_base.NodeTest):
self.assertEqual(kwargs, call[1])
self.check_fsm([pxe_filter.Events.sync])
def test_sync_with_blacklist(self):
def _test_sync_with_blacklist(self, expected_port):
self.driver = iptables.IptablesFilter()
self.mock_iptables = self.useFixture(
fixtures.MockPatchObject(self.driver, '_iptables')).mock
self.mock__get_blacklist.return_value = ['AA:BB:CC:DD:EE:FF']
self.mock_should_enable_dhcp.return_value = True
_iptables_expected_args = [
('-D', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
'67', '-j', self.driver.new_chain),
expected_port, '-j', self.driver.new_chain),
('-F', self.driver.new_chain),
('-X', self.driver.new_chain),
('-N', self.driver.new_chain),
@ -178,9 +192,9 @@ class TestIptablesDriver(test_base.NodeTest):
self.mock__get_blacklist.return_value[0], '-j', 'DROP'),
('-A', self.driver.new_chain, '-j', 'ACCEPT'),
('-I', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
'67', '-j', self.driver.new_chain),
expected_port, '-j', self.driver.new_chain),
('-D', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
'67', '-j', self.driver.chain),
expected_port, '-j', self.driver.chain),
('-F', self.driver.chain),
('-X', self.driver.chain),
('-E', self.driver.new_chain, self.driver.chain)
@ -203,7 +217,18 @@ class TestIptablesDriver(test_base.NodeTest):
self.mock__get_blacklist.assert_called_once_with(self.mock_ironic)
self.assertFalse(self.mock_iptables.called)
def test__iptables_clean_cache_on_error(self):
def test_sync_with_blacklist_ipv4(self):
CONF.set_override('ip_version', '4', 'iptables')
self._test_sync_with_blacklist('67')
def test_sync_with_blacklist_ipv6(self):
CONF.set_override('ip_version', '6', 'iptables')
self._test_sync_with_blacklist('547')
def _test__iptables_clean_cache_on_error(self, expected_port):
self.driver = iptables.IptablesFilter()
self.mock_iptables = self.useFixture(
fixtures.MockPatchObject(self.driver, '_iptables')).mock
self.mock__get_blacklist.return_value = ['AA:BB:CC:DD:EE:FF']
self.mock_should_enable_dhcp.return_value = True
@ -217,7 +242,7 @@ class TestIptablesDriver(test_base.NodeTest):
syncs_expected_args = [
# driver reset
('-D', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
'67', '-j', self.driver.new_chain),
expected_port, '-j', self.driver.new_chain),
('-F', self.driver.new_chain),
('-X', self.driver.new_chain),
('-N', self.driver.new_chain),
@ -226,9 +251,9 @@ class TestIptablesDriver(test_base.NodeTest):
self.mock__get_blacklist.return_value[0], '-j', 'DROP'),
('-A', self.driver.new_chain, '-j', 'ACCEPT'),
('-I', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
'67', '-j', self.driver.new_chain),
expected_port, '-j', self.driver.new_chain),
('-D', 'INPUT', '-i', 'br-ctlplane', '-p', 'udp', '--dport',
'67', '-j', self.driver.chain),
expected_port, '-j', self.driver.chain),
('-F', self.driver.chain),
('-X', self.driver.chain),
('-E', self.driver.new_chain, self.driver.chain)
@ -247,6 +272,24 @@ class TestIptablesDriver(test_base.NodeTest):
self.assertEqual(args, call[0], 'idx: %s' % idx)
self.mock__get_blacklist.assert_called_once_with(self.mock_ironic)
def test__iptables_clean_cache_on_error_ipv4(self):
CONF.set_override('ip_version', '4', 'iptables')
self._test__iptables_clean_cache_on_error('67')
def test__iptables_clean_cache_on_error_ipv6(self):
CONF.set_override('ip_version', '6', 'iptables')
self._test__iptables_clean_cache_on_error('547')
def test_iptables_command_ipv4(self):
CONF.set_override('ip_version', '4', 'iptables')
driver = iptables.IptablesFilter()
self.assertEqual(driver._cmd_iptables, 'iptables')
def test_iptables_command_ipv6(self):
CONF.set_override('ip_version', '6', 'iptables')
driver = iptables.IptablesFilter()
self.assertEqual(driver._cmd_iptables, 'ip6tables')
class Test_ShouldEnableDhcp(test_base.BaseTest):
def setUp(self):

View File

@ -0,0 +1,8 @@
---
features:
- |
Adds a configuration option ``[iptables]ip_version`` to specify the
desired ip version for the iptables pxe filter, possible values are ``4``
and ``6``, the default value is ``4``. When set to ``6``, the iptables
pxe filter will use ``ip6tables`` command to manage rules for the DHCPv6
port ``547``.

View File

@ -2,8 +2,9 @@
[Filters]
# ironic-inspector-rootwrap command filters for firewall manipulation
# ironic_inspector/firewall.py
# ironic_inspector/pxe_filter/iptables.py
iptables: CommandFilter, iptables, root
ip6tables: CommandFilter, ip6tables, root
# ironic-inspector-rootwrap command filters for systemctl manipulation of the dnsmasq service
# ironic_inspector/pxe_filter/dnsmasq.py