def __init__(self, ip_type, iptables_mgr): super(MasqueradeManager, self).__init__(qualifier=str(ip_type)) assert ip_type in (IPV4, IPV6) assert iptables_mgr.table == "nat" self.ip_type = ip_type self.pools_by_id = {} self._iptables_mgr = iptables_mgr ip_family = "inet" if ip_type == IPV4 else "inet6" self._all_pools_ipset = Ipset(ALL_POOLS_SET_NAME, ALL_POOLS_SET_NAME + "-tmp", ip_family, "hash:net") self._masq_pools_ipset = Ipset(MASQ_POOLS_SET_NAME, MASQ_POOLS_SET_NAME + "-tmp", ip_family, "hash:net") self._dirty = False
class TestIpset(BaseTestCase): def setUp(self): super(TestIpset, self).setUp() self.ipset = Ipset("foo", "foo-tmp", "inet") @patch("calico.felix.futils.check_call", autospec=True) def test_mainline(self, m_check_call): self.ipset.replace_members(set(["10.0.0.1"])) m_check_call.assert_called_once_with( ["ipset", "restore"], input_str='create foo hash:ip family inet --exist\n' 'create foo-tmp hash:ip family inet --exist\n' 'flush foo-tmp\n' 'add foo-tmp 10.0.0.1\n' 'swap foo foo-tmp\n' 'destroy foo-tmp\n' 'COMMIT\n' ) @patch("calico.felix.futils.check_call", autospec=True) def test_ensure_exists(self, m_check_call): self.ipset.ensure_exists() m_check_call.assert_called_once_with( ["ipset", "restore"], input_str='create foo hash:ip family inet --exist\n' 'COMMIT\n' ) @patch("calico.felix.futils.call_silent", autospec=True) def test_delete(self, m_call_silent): self.ipset.delete() self.assertEqual( m_call_silent.mock_calls, [ call(["ipset", "destroy", "foo"]), call(["ipset", "destroy", "foo-tmp"]), ] )
def setUp(self): super(TestIpset, self).setUp() self.ipset = Ipset("foo", "foo-tmp", "inet")
class TestIpset(BaseTestCase): def setUp(self): super(TestIpset, self).setUp() self.ipset = Ipset("foo", "foo-tmp", "inet") @patch("calico.felix.futils.check_call", autospec=True) def test_replace_members(self, m_check_call): self.ipset.replace_members(set(["10.0.0.1"])) exp_calls = [ call(["ipset", "destroy", "foo-tmp"]), call(["ipset", "list", "foo"]), call(["ipset", "restore"], input_str='create foo-tmp hash:ip family inet ' 'maxelem 1048576 --exist\n' 'flush foo-tmp\n' 'add foo-tmp 10.0.0.1\n' 'swap foo foo-tmp\n' 'destroy foo-tmp\n' 'COMMIT\n') ] self.assertEqual(m_check_call.mock_calls, exp_calls) @patch("calico.felix.futils.check_call", autospec=True) def test_replace_members_delete_fails(self, m_check_call): m_check_call.side_effect = iter( [FailedSystemCall("Blah", [], 1, None, "err"), None, None, None]) self.ipset.replace_members(set(["10.0.0.1"])) exp_calls = [ call(["ipset", "destroy", "foo-tmp"]), call(['ipset', 'list', 'foo-tmp']), call(['ipset', 'list', 'foo']), call(["ipset", "restore"], input_str='create foo-tmp hash:ip family inet ' 'maxelem 1048576 --exist\n' 'flush foo-tmp\n' 'add foo-tmp 10.0.0.1\n' 'swap foo foo-tmp\n' 'destroy foo-tmp\n' 'COMMIT\n') ] self.assertEqual(m_check_call.mock_calls, exp_calls) @patch("calico.felix.futils.check_call", autospec=True) def test_apply_changes(self, m_check_call): added = set(["10.0.0.2"]) removed = set(["10.0.0.1"]) self.ipset.apply_changes(added, removed) self.assertEqual(m_check_call.mock_calls, [ call(["ipset", "restore"], input_str='del foo 10.0.0.1\n' 'add foo 10.0.0.2\n' 'COMMIT\n') ]) @patch("calico.felix.futils.check_call", autospec=True, side_effect=FailedSystemCall("Blah", [], None, None, "err")) def test_apply_changes_err(self, m_check_call): # First call to update_members will fail, leading to a retry. added = set(["10.0.0.2"]) removed = set(["10.0.0.1"]) self.assertRaises(FailedSystemCall, self.ipset.apply_changes, added, removed) @patch("calico.felix.futils.check_call", autospec=True) def test_ensure_exists(self, m_check_call): self.ipset.ensure_exists() m_check_call.assert_called_once_with( ["ipset", "restore"], input_str='create foo hash:ip family inet maxelem 1048576 --exist\n' 'COMMIT\n') @patch("calico.felix.futils.call_silent", autospec=True) def test_delete(self, m_call_silent): self.ipset.delete() self.assertEqual(m_call_silent.mock_calls, [ call(["ipset", "destroy", "foo"]), call(["ipset", "destroy", "foo-tmp"]), ]) @patch("calico.felix.futils.check_call", autospec=True) def test_list_ipset_names(self, m_check_call): m_check_call.return_value = CommandOutput(IPSET_LIST_OUTPUT, "") self.assertEqual(list_ipset_names(), ['felix-v4-calico_net', 'felix-v6-calico_net'])
class MasqueradeManager(Actor): def __init__(self, ip_type, iptables_mgr): super(MasqueradeManager, self).__init__(qualifier=str(ip_type)) assert ip_type in (IPV4, IPV6) assert iptables_mgr.table == "nat" self.ip_type = ip_type self.pools_by_id = {} self._iptables_mgr = iptables_mgr ip_family = "inet" if ip_type == IPV4 else "inet6" self._all_pools_ipset = Ipset(ALL_POOLS_SET_NAME, ALL_POOLS_SET_NAME + "-tmp", ip_family, "hash:net") self._masq_pools_ipset = Ipset(MASQ_POOLS_SET_NAME, MASQ_POOLS_SET_NAME + "-tmp", ip_family, "hash:net") self._dirty = False @actor_message() def apply_snapshot(self, pools_by_id): _log.info("Applying IPAM pool snapshot with %s pools", len(pools_by_id)) self.pools_by_id.clear() self.pools_by_id.update(pools_by_id) self._dirty = True @actor_message() def on_ipam_pool_updated(self, pool_id, pool): if self.pools_by_id.get(pool_id) != pool: if pool is None: _log.info("IPAM pool deleted: %s", pool_id) del self.pools_by_id[pool_id] else: _log.info("IPAM pool %s updated: %s", pool_id, pool) self.pools_by_id[pool_id] = pool self._dirty = True def _finish_msg_batch(self, batch, results): _log.debug("Finishing batch of IPAM pool changes") if self._dirty: _log.info("Marked as dirty, looking for masq-enabled pools") masq_enabled_cidrs = set() all_cidrs = set() for pool in self.pools_by_id.itervalues(): all_cidrs.add(pool["cidr"]) if pool.get("masquerade", False): masq_enabled_cidrs.add(pool["cidr"]) if masq_enabled_cidrs: _log.info("There are masquerade-enabled pools present. " "Updating.") self._all_pools_ipset.replace_members(all_cidrs) self._masq_pools_ipset.replace_members(masq_enabled_cidrs) # Enable masquerading for traffic coming from pools that # have it enabled only when the traffic is heading to an IP # that isn't in any Calico-owned pool. (We assume that NAT # is not required for Calico-owned IPs.) self._iptables_mgr.ensure_rule_inserted(MASQ_RULE_FRAGMENT, async=True) else: _log.info("No masquerade-enabled pools present. " "Removing rules and ipsets.") # Ensure that the rule doesn't exist before we try to remove # our ipsets. Have to make a blocking call so that we don't # try to remove the ipsets before we've cleaned up the rule # that references them. self._iptables_mgr.ensure_rule_removed(MASQ_RULE_FRAGMENT, async=False) # Safe to call even if the ipsets don't exist: self._all_pools_ipset.delete() self._masq_pools_ipset.delete() self._dirty = False _log.info("Finished refreshing ipsets")
class TestIpset(BaseTestCase): def setUp(self): super(TestIpset, self).setUp() self.ipset = Ipset("foo", "foo-tmp", "inet") @patch("calico.felix.futils.check_call", autospec=True) def test_replace_members(self, m_check_call): self.ipset.replace_members(set(["10.0.0.1"])) exp_calls = [ call(["ipset", "destroy", "foo-tmp"]), call(["ipset", "list", "foo"]), call( ["ipset", "restore"], input_str='create foo-tmp hash:ip family inet ' 'maxelem 1048576 --exist\n' 'flush foo-tmp\n' 'add foo-tmp 10.0.0.1\n' 'swap foo foo-tmp\n' 'destroy foo-tmp\n' 'COMMIT\n' ) ] self.assertEqual(m_check_call.mock_calls, exp_calls) @patch("calico.felix.futils.check_call", autospec=True) def test_replace_members_delete_fails(self, m_check_call): m_check_call.side_effect = iter([ FailedSystemCall("Blah", [], 1, None, "err"), None, None, None]) self.ipset.replace_members(set(["10.0.0.1"])) exp_calls = [ call(["ipset", "destroy", "foo-tmp"]), call(['ipset', 'list', 'foo-tmp']), call(['ipset', 'list', 'foo']), call( ["ipset", "restore"], input_str='create foo-tmp hash:ip family inet ' 'maxelem 1048576 --exist\n' 'flush foo-tmp\n' 'add foo-tmp 10.0.0.1\n' 'swap foo foo-tmp\n' 'destroy foo-tmp\n' 'COMMIT\n' ) ] self.assertEqual(m_check_call.mock_calls, exp_calls) @patch("calico.felix.futils.check_call", autospec=True) def test_apply_changes(self, m_check_call): added = set(["10.0.0.2"]) removed = set(["10.0.0.1"]) self.ipset.apply_changes(added, removed) self.assertEqual( m_check_call.mock_calls, [call(["ipset", "restore"], input_str='del foo 10.0.0.1\n' 'add foo 10.0.0.2\n' 'COMMIT\n')] ) @patch("calico.felix.futils.check_call", autospec=True, side_effect=FailedSystemCall("Blah", [], None, None, "err")) def test_apply_changes_err(self, m_check_call): # First call to update_members will fail, leading to a retry. added = set(["10.0.0.2"]) removed = set(["10.0.0.1"]) self.assertRaises(FailedSystemCall, self.ipset.apply_changes, added, removed) @patch("calico.felix.futils.check_call", autospec=True) def test_ensure_exists(self, m_check_call): self.ipset.ensure_exists() m_check_call.assert_called_once_with( ["ipset", "restore"], input_str='create foo hash:ip family inet maxelem 1048576 --exist\n' 'COMMIT\n' ) @patch("calico.felix.futils.call_silent", autospec=True) def test_delete(self, m_call_silent): self.ipset.delete() self.assertEqual( m_call_silent.mock_calls, [ call(["ipset", "destroy", "foo"]), call(["ipset", "destroy", "foo-tmp"]), ] ) @patch("calico.felix.futils.check_call", autospec=True) def test_list_ipset_names(self, m_check_call): m_check_call.return_value = CommandOutput(IPSET_LIST_OUTPUT, "") self.assertEqual(list_ipset_names(), ['felix-v4-calico_net', 'felix-v6-calico_net'])
class TestIpset(BaseTestCase): def setUp(self): super(TestIpset, self).setUp() self.ipset = Ipset("foo", "foo-tmp", "inet") @patch("calico.felix.futils.check_call", autospec=True) def test_replace_members(self, m_check_call): self.ipset.replace_members(set(["10.0.0.1"])) m_check_call.assert_called_once_with( ["ipset", "restore"], input_str='create foo hash:ip family inet --exist\n' 'create foo-tmp hash:ip family inet --exist\n' 'flush foo-tmp\n' 'add foo-tmp 10.0.0.1\n' 'swap foo foo-tmp\n' 'destroy foo-tmp\n' 'COMMIT\n' ) @patch("calico.felix.futils.check_call", autospec=True) def test_update_members(self, m_check_call): old = set(["10.0.0.2"]) new = set(["10.0.0.1", "10.0.0.2"]) self.ipset.update_members(old, new) old = set(["10.0.0.1", "10.0.0.2"]) new = set(["10.0.0.1", "1.2.3.4"]) self.ipset.update_members(old, new) calls = [call(["ipset", "restore"], input_str='add foo 10.0.0.1\nCOMMIT\n'), call(["ipset", "restore"], input_str='del foo 10.0.0.2\n' 'add foo 1.2.3.4\n' 'COMMIT\n')] self.assertEqual(m_check_call.call_count, 2) m_check_call.assert_has_calls(calls) @patch("calico.felix.futils.check_call", autospec=True, side_effect=iter([ FailedSystemCall("Blah", [], None, None, "err"), None])) def test_update_members_err(self, m_check_call): # First call to update_members will fail, leading to a retry. old = set(["10.0.0.2"]) new = set(["10.0.0.1"]) self.ipset.update_members(old, new) calls = [call(["ipset", "restore"], input_str='del foo 10.0.0.2\n' 'add foo 10.0.0.1\n' 'COMMIT\n'), call(["ipset", "restore"], input_str='create foo hash:ip family inet --exist\n' 'create foo-tmp hash:ip family inet --exist\n' 'flush foo-tmp\n' 'add foo-tmp 10.0.0.1\n' 'swap foo foo-tmp\n' 'destroy foo-tmp\n' 'COMMIT\n')] self.assertEqual(m_check_call.call_count, 2) m_check_call.assert_has_calls(calls) @patch("calico.felix.futils.check_call", autospec=True) def test_ensure_exists(self, m_check_call): self.ipset.ensure_exists() m_check_call.assert_called_once_with( ["ipset", "restore"], input_str='create foo hash:ip family inet --exist\n' 'COMMIT\n' ) @patch("calico.felix.futils.call_silent", autospec=True) def test_delete(self, m_call_silent): self.ipset.delete() self.assertEqual( m_call_silent.mock_calls, [ call(["ipset", "destroy", "foo"]), call(["ipset", "destroy", "foo-tmp"]), ] )
class TestIpset(BaseTestCase): def setUp(self): super(TestIpset, self).setUp() self.ipset = Ipset("foo", "foo-tmp", "inet") @patch("calico.felix.futils.check_call", autospec=True) def test_replace_members(self, m_check_call): self.ipset.replace_members(set(["10.0.0.1"])) m_check_call.assert_called_once_with( ["ipset", "restore"], input_str='create foo hash:ip family inet --exist\n' 'create foo-tmp hash:ip family inet --exist\n' 'flush foo-tmp\n' 'add foo-tmp 10.0.0.1\n' 'swap foo foo-tmp\n' 'destroy foo-tmp\n' 'COMMIT\n') @patch("calico.felix.futils.check_call", autospec=True) def test_update_members(self, m_check_call): old = set(["10.0.0.2"]) new = set(["10.0.0.1", "10.0.0.2"]) self.ipset.update_members(old, new) old = set(["10.0.0.1", "10.0.0.2"]) new = set(["10.0.0.1", "1.2.3.4"]) self.ipset.update_members(old, new) calls = [ call(["ipset", "restore"], input_str='add foo 10.0.0.1\nCOMMIT\n'), call(["ipset", "restore"], input_str='del foo 10.0.0.2\n' 'add foo 1.2.3.4\n' 'COMMIT\n') ] self.assertEqual(m_check_call.call_count, 2) m_check_call.assert_has_calls(calls) @patch("calico.felix.futils.check_call", autospec=True, side_effect=iter( [FailedSystemCall("Blah", [], None, None, "err"), None])) def test_update_members_err(self, m_check_call): # First call to update_members will fail, leading to a retry. old = set(["10.0.0.2"]) new = set(["10.0.0.1"]) self.ipset.update_members(old, new) calls = [ call(["ipset", "restore"], input_str='del foo 10.0.0.2\n' 'add foo 10.0.0.1\n' 'COMMIT\n'), call(["ipset", "restore"], input_str='create foo hash:ip family inet --exist\n' 'create foo-tmp hash:ip family inet --exist\n' 'flush foo-tmp\n' 'add foo-tmp 10.0.0.1\n' 'swap foo foo-tmp\n' 'destroy foo-tmp\n' 'COMMIT\n') ] self.assertEqual(m_check_call.call_count, 2) m_check_call.assert_has_calls(calls) @patch("calico.felix.futils.check_call", autospec=True) def test_ensure_exists(self, m_check_call): self.ipset.ensure_exists() m_check_call.assert_called_once_with( ["ipset", "restore"], input_str='create foo hash:ip family inet --exist\n' 'COMMIT\n') @patch("calico.felix.futils.call_silent", autospec=True) def test_delete(self, m_call_silent): self.ipset.delete() self.assertEqual(m_call_silent.mock_calls, [ call(["ipset", "destroy", "foo"]), call(["ipset", "destroy", "foo-tmp"]), ])