Пример #1
0
 def test_set_routes_arp_ipv4_only(self):
     type = futils.IPV4
     ips = set(["1.2.3.4", "2.3.4.5"])
     interface = "tapabcdef"
     mac = stub_utils.get_mac()
     with self.assertRaisesRegexp(ValueError, "reset_arp may only be supplied for " "IPv4"):
         devices.set_routes(futils.IPV6, ips, interface, mac=mac, reset_arp=True)
Пример #2
0
    def test_add_route(self):
        tap = "tap" + str(uuid.uuid4())[:11]
        mac = stub_utils.get_mac()
        retcode = futils.CommandOutput("", "")

        type = futils.IPV4
        ip = "1.2.3.4"
        with mock.patch('calico.felix.futils.check_call', return_value=retcode):
            devices.add_route(type, ip, tap, mac)
            futils.check_call.assert_any_call(['arp', '-s', ip, mac, '-i', tap])
            futils.check_call.assert_called_with(["ip", "route", "replace", ip, "dev", tap])

        with self.assertRaisesRegexp(ValueError,
                                     "mac must be supplied if ip is provided"):
            devices.add_route(type, ip, tap, None)

        type = futils.IPV6
        ip = "2001::"
        with mock.patch('calico.felix.futils.check_call', return_value=retcode):
            devices.add_route(type, ip, tap, mac)
            futils.check_call.assert_called_with(["ip", "-6", "route", "replace", ip, "dev", tap])

        with self.assertRaisesRegexp(ValueError,
                                     "mac must be supplied if ip is provided"):
            devices.add_route(type, ip, tap, None)
Пример #3
0
    def test_add_route(self):
        tap = "tap" + str(uuid.uuid4())[:11]
        mac = stub_utils.get_mac()
        retcode = futils.CommandOutput("", "")

        type = futils.IPV4
        ip = "1.2.3.4"
        with mock.patch('calico.felix.futils.check_call',
                        return_value=retcode):
            devices.add_route(type, ip, tap, mac)
            futils.check_call.assert_any_call(
                ['arp', '-s', ip, mac, '-i', tap])
            futils.check_call.assert_called_with(
                ["ip", "route", "replace", ip, "dev", tap])

        with mock.patch("calico.felix.futils.check_call") as m_check_call:
            devices.add_route(type, ip, tap, None)

        type = futils.IPV6
        ip = "2001::"
        with mock.patch('calico.felix.futils.check_call',
                        return_value=retcode):
            devices.add_route(type, ip, tap, mac)
            futils.check_call.assert_called_with(
                ["ip", "-6", "route", "replace", ip, "dev", tap])

        with mock.patch("calico.felix.futils.check_call") as m_check_call:
            devices.add_route(type, ip, tap, None)
Пример #4
0
 def test_set_routes_mac_required(self):
     type = futils.IPV4
     ips = set(["1.2.3.4", "2.3.4.5"])
     interface = "tapabcdef"
     mac = stub_utils.get_mac()
     with self.assertRaisesRegexp(ValueError, "mac must be supplied if ips is not " "empty"):
         devices.set_routes(type, ips, interface)
Пример #5
0
 def test_set_routes_mac_required(self):
     type = futils.IPV4
     ips = set(["1.2.3.4", "2.3.4.5"])
     interface = "tapabcdef"
     mac = stub_utils.get_mac()
     with self.assertRaisesRegexp(ValueError,
                                  "mac must be supplied if ips is not "
                                  "empty"):
         devices.set_routes(type, ips, interface)
Пример #6
0
 def test_set_routes_arp_ipv4_only(self):
     type = futils.IPV4
     ips = set(["1.2.3.4", "2.3.4.5"])
     interface = "tapabcdef"
     mac = stub_utils.get_mac()
     with self.assertRaisesRegexp(ValueError,
                                  "reset_arp may only be supplied for "
                                  "IPv4"):
         devices.set_routes(futils.IPV6, ips, interface, mac=mac,
                            reset_arp=True)
Пример #7
0
 def test_set_routes_nothing_to_do(self, m_remove_conntrack):
     type = futils.IPV4
     ips = set(["1.2.3.4", "2.3.4.5"])
     retcode = futils.CommandOutput("", "")
     interface = "tapabcdef"
     mac = stub_utils.get_mac()
     with mock.patch("calico.felix.futils.check_call", return_value=retcode):
         with mock.patch("calico.felix.devices.list_interface_ips", return_value=ips):
             devices.set_routes(type, ips, interface, mac)
             self.assertEqual(futils.check_call.call_count, 0)
             m_remove_conntrack.assert_called_once_with(set(), 4)
Пример #8
0
 def test_set_routes_nothing_to_do(self):
     type = futils.IPV4
     ips = set(["1.2.3.4", "2.3.4.5"])
     retcode = futils.CommandOutput("", "")
     interface = "tapabcdef"
     mac = stub_utils.get_mac()
     with mock.patch('calico.felix.futils.check_call',
                     return_value=retcode):
         with mock.patch('calico.felix.devices.list_interface_route_ips',
                         return_value=ips):
             devices.set_routes(type, ips, interface, mac)
             self.assertEqual(futils.check_call.call_count, 0)
Пример #9
0
    def test_profile_id_update_triggers_iptables(self):
        combined_id = EndpointId("host_id", "orchestrator_id",
                                 "workload_id", "endpoint_id")
        ip_type = futils.IPV4
        local_ep = self.get_local_endpoint(combined_id, ip_type)

        ips = ["10.0.0.1"]
        iface = "tapabcdef"
        mac = stub_utils.get_mac()
        data = {'endpoint': "endpoint_id", 'mac': mac,
                'name': iface, 'ipv4_nets': ips, 'profile_ids': ["prof1"]}
        local_ep._pending_endpoint = data.copy()

        # First update with endpoint not yet set, should trigger full sync.
        local_ep._apply_endpoint_update()
        self.assertEqual(local_ep.endpoint, data)
        self.assertFalse(local_ep._iptables_in_sync)
        self.assertFalse(local_ep._device_in_sync)

        local_ep._iptables_in_sync = True
        local_ep._device_in_sync = True

        # No-op update
        local_ep._pending_endpoint = data.copy()
        local_ep._apply_endpoint_update()
        self.assertTrue(local_ep._iptables_in_sync)
        self.assertTrue(local_ep._device_in_sync)

        # Profiles update.  Should update iptables.
        data = {'endpoint': "endpoint_id", 'mac': mac,
                'name': iface, 'ipv4_nets': ips, 'profile_ids': ["prof2"]}
        local_ep._pending_endpoint = data.copy()
        local_ep._apply_endpoint_update()
        self.assertFalse(local_ep._iptables_in_sync)
        local_ep._iptables_in_sync = True
        self.assertTrue(local_ep._device_in_sync)

        # IP update.  Should update routing.
        data = {'endpoint': "endpoint_id", 'mac': mac,
                'name': iface, 'ipv4_nets': ["10.0.0.2"],
                'profile_ids': ["prof2"]}
        local_ep._pending_endpoint = data.copy()
        local_ep._apply_endpoint_update()
        self.assertTrue(local_ep._iptables_in_sync)
        self.assertFalse(local_ep._device_in_sync)
        local_ep._device_in_sync = True

        # Delete, should update everything.
        local_ep._pending_endpoint = None
        local_ep._apply_endpoint_update()
        self.assertFalse(local_ep._iptables_in_sync)
        self.assertFalse(local_ep._device_in_sync)
Пример #10
0
    def test_on_endpoint_update_delete_fail(self):
        combined_id = EndpointId("host_id", "orchestrator_id",
                                 "workload_id", "endpoint_id")
        ip_type = futils.IPV4
        local_ep = self.get_local_endpoint(combined_id, ip_type)

        ips = ["1.2.3.4/32"]
        iface = "tapabcdef"
        data = {
            'state': "active",
            'endpoint': "endpoint_id",
            'mac': stub_utils.get_mac(),
            'name': iface,
            'ipv4_nets': ips,
            'profile_ids': ["prof1"]
        }

        # Report an initial update (endpoint creation) and check configured
        with mock.patch('calico.felix.devices.remove_conntrack_flows') as m_rem_conntrack,\
                mock.patch('calico.felix.devices.set_routes') as m_set_routes,\
                mock.patch('calico.felix.devices.configure_interface_ipv4') as m_conf,\
                mock.patch('calico.felix.devices.interface_exists') as m_iface_exists,\
                mock.patch('calico.felix.devices.interface_up') as m_iface_up:
            m_iface_exists.return_value = True
            m_iface_up.return_value = True

            local_ep.on_endpoint_update(data, async=True)
            self.step_actor(local_ep)

            self.assertEqual(local_ep._mac, data['mac'])
            m_conf.assert_called_once_with(iface)
            m_set_routes.assert_called_once_with(ip_type,
                                                 set(["1.2.3.4"]),
                                                 iface,
                                                 data['mac'],
                                                 reset_arp=True)
            self.assertFalse(m_rem_conntrack.called)

        # Send empty data, which deletes the endpoint.  Raise an exception
        # from set_routes to check that it's handled.
        with mock.patch('calico.felix.devices.set_routes') as m_set_routes,\
               mock.patch('calico.felix.devices.interface_exists', return_value=True),\
               mock.patch('calico.felix.devices.remove_conntrack_flows') as m_rem_conntrack:
            m_set_routes.side_effect = FailedSystemCall("", [], 1, "", "")
            local_ep.on_endpoint_update(None, async=True)
            self.step_actor(local_ep)
            m_set_routes.assert_called_once_with(ip_type, set(),
                                                 data["name"], None)
            # Should clean up conntrack entries for all IPs.
            m_rem_conntrack.assert_called_once_with(
                set(['1.2.3.4']), 4
            )
Пример #11
0
    def test_on_interface_update_v4(self):
        combined_id = EndpointId("host_id", "orchestrator_id",
                                 "workload_id", "endpoint_id")
        ip_type = futils.IPV4
        local_ep = self.get_local_endpoint(combined_id, ip_type)

        ips = ["1.2.3.4"]
        iface = "tapabcdef"
        data = {
            'state': "active",
            'endpoint': "endpoint_id",
            'mac': stub_utils.get_mac(),
            'name': iface,
            'ipv4_nets': ips,
            'profile_ids': ["prof1"]
        }

        # We can only get on_interface_update calls after the first
        # on_endpoint_update, so trigger that.
        with nested(
                mock.patch('calico.felix.devices.set_routes'),
                mock.patch('calico.felix.devices.configure_interface_ipv4'),
                mock.patch('calico.felix.devices.interface_up'),
        ) as [m_set_routes, m_conf, m_iface_up]:
                m_iface_up.return_value = False
                local_ep.on_endpoint_update(data, async=True)
                self.step_actor(local_ep)
                self.assertEqual(local_ep._mac, data['mac'])
                m_conf.assert_called_once_with(iface)
                m_set_routes.assert_called_once_with(ip_type,
                                                     set(ips),
                                                     iface,
                                                     data['mac'],
                                                     reset_arp=True)
                self.assertTrue(local_ep._device_in_sync)

        # Now pretend to get an interface update - does all the same work.
        with mock.patch('calico.felix.devices.set_routes') as m_set_routes:
            with mock.patch('calico.felix.devices.'
                            'configure_interface_ipv4') as m_conf:
                local_ep.on_interface_update(True, async=True)
                self.step_actor(local_ep)
                m_conf.assert_called_once_with(iface)
                m_set_routes.assert_called_once_with(ip_type,
                                                     set(ips),
                                                     iface,
                                                     data['mac'],
                                                     reset_arp=True)
                self.assertTrue(local_ep._device_in_sync)
Пример #12
0
    def test_set_routes_mainline(self):
        type = futils.IPV4
        ips = set(["1.2.3.4", "2.3.4.5"])
        interface = "tapabcdef"
        mac = stub_utils.get_mac()
        calls = [mock.call(['arp', '-s', "1.2.3.4", mac, '-i', interface]),
                 mock.call(["ip", "route", "replace", "1.2.3.4", "dev", interface]),
                 mock.call(['arp', '-s', "2.3.4.5", mac, '-i', interface]),
                 mock.call(["ip", "route", "replace", "2.3.4.5", "dev", interface])]

        with mock.patch('calico.felix.futils.check_call',
                        return_value=futils.CommandOutput("", "")):
            with mock.patch('calico.felix.devices.list_interface_route_ips',
                            return_value=set()):
                devices.set_routes(type, ips, interface, mac)
                self.assertEqual(futils.check_call.call_count, len(calls))
                futils.check_call.assert_has_calls(calls, any_order=True)
Пример #13
0
    def test_set_routes_mainline(self):
        type = futils.IPV4
        ips = set(["1.2.3.4", "2.3.4.5"])
        interface = "tapabcdef"
        mac = stub_utils.get_mac()
        calls = [mock.call(['arp', '-s', "1.2.3.4", mac, '-i', interface]),
                 mock.call(["ip", "route", "replace", "1.2.3.4", "dev", interface]),
                 mock.call(['arp', '-s', "2.3.4.5", mac, '-i', interface]),
                 mock.call(["ip", "route", "replace", "2.3.4.5", "dev", interface])]

        with mock.patch('calico.felix.futils.check_call',
                        return_value=futils.CommandOutput("", "")):
            with mock.patch('calico.felix.devices.list_interface_route_ips',
                            return_value=set()):
                devices.set_routes(type, ips, interface, mac)
                self.assertEqual(futils.check_call.call_count, len(calls))
                futils.check_call.assert_has_calls(calls, any_order=True)
Пример #14
0
    def test_set_routes_mainline(self, m_remove_conntrack):
        type = futils.IPV4
        ips = set(["1.2.3.4", "2.3.4.5"])
        interface = "tapabcdef"
        mac = stub_utils.get_mac()
        calls = [
            mock.call(["arp", "-s", "1.2.3.4", mac, "-i", interface]),
            mock.call(["ip", "route", "replace", "1.2.3.4", "dev", interface]),
            mock.call(["arp", "-s", "2.3.4.5", mac, "-i", interface]),
            mock.call(["ip", "route", "replace", "2.3.4.5", "dev", interface]),
        ]

        with mock.patch("calico.felix.futils.check_call", return_value=futils.CommandOutput("", "")):
            with mock.patch("calico.felix.devices.list_interface_ips", return_value=set()):
                devices.set_routes(type, ips, interface, mac)
                self.assertEqual(futils.check_call.call_count, len(calls))
                futils.check_call.assert_has_calls(calls, any_order=True)
                m_remove_conntrack.assert_called_once_with(set(), 4)
Пример #15
0
 def test_set_routes_changed_ips_reset_arp(self, m_remove_conntrack):
     type = futils.IPV4
     ips = set(["1.2.3.4", "2.3.4.5"])
     interface = "tapabcdef"
     mac = stub_utils.get_mac()
     retcode = futils.CommandOutput("", "")
     current_ips = set(["2.3.4.5", "3.4.5.6"])
     calls = [mock.call(['arp', '-s', "1.2.3.4", mac, '-i', interface]),
              mock.call(["ip", "route", "replace", "1.2.3.4", "dev", interface]),
              mock.call(['arp', '-s', "2.3.4.5", mac, '-i', interface]),
              mock.call(['arp', '-d', "3.4.5.6", '-i', interface]),
              mock.call(["ip", "route", "del", "3.4.5.6", "dev", interface])]
     with mock.patch('calico.felix.futils.check_call', return_value=retcode):
         with mock.patch('calico.felix.devices.list_interface_ips',
                         return_value=current_ips):
             devices.set_routes(type, ips, interface, mac, reset_arp=True)
             self.assertEqual(futils.check_call.call_count, len(calls))
             futils.check_call.assert_has_calls(calls, any_order=True)
             m_remove_conntrack.assert_called_once_with(set(["3.4.5.6"]), 4)
Пример #16
0
 def test_set_routes_changed_ips_reset_arp(self, m_remove_conntrack):
     type = futils.IPV4
     ips = set(["1.2.3.4", "2.3.4.5"])
     interface = "tapabcdef"
     mac = stub_utils.get_mac()
     retcode = futils.CommandOutput("", "")
     current_ips = set(["2.3.4.5", "3.4.5.6"])
     calls = [mock.call(['arp', '-s', "1.2.3.4", mac, '-i', interface]),
              mock.call(["ip", "route", "replace", "1.2.3.4", "dev", interface]),
              mock.call(['arp', '-s', "2.3.4.5", mac, '-i', interface]),
              mock.call(['arp', '-d', "3.4.5.6", '-i', interface]),
              mock.call(["ip", "route", "del", "3.4.5.6", "dev", interface])]
     with mock.patch('calico.felix.futils.check_call', return_value=retcode):
         with mock.patch('calico.felix.devices.list_interface_route_ips',
                         return_value=current_ips):
             devices.set_routes(type, ips, interface, mac, reset_arp=True)
             self.assertEqual(futils.check_call.call_count, len(calls))
             futils.check_call.assert_has_calls(calls, any_order=True)
             m_remove_conntrack.assert_called_once_with(set(["3.4.5.6"]), 4)
Пример #17
0
    def test_tiered_policy_mainline(self, m_devices):
        self.config.plugins["iptables_generator"] = self.m_ipt_gen
        ep = self.get_local_endpoint(ENDPOINT_ID, futils.IPV4)
        mac = stub_utils.get_mac()
        ep.on_endpoint_update(
            {
                'state': "active",
                'endpoint': "endpoint_id",
                'mac': mac,
                'name': "tap1234",
                'ipv4_nets': ["10.0.0.1"],
                'profile_ids': ["prof1"]
            },
            async=True)
        self.step_actor(ep)

        self.assertEqual(
            self.m_ipt_gen.endpoint_updates.mock_calls,
            [
                mock.call(4, 'd', '1234', mac, ['prof1'], {}),
            ]
        )
        self.m_ipt_gen.endpoint_updates.reset_mock()

        tiers = OrderedDict()
        t1_1 = TieredPolicyId("t1", "t1_1")
        t1_2 = TieredPolicyId("t1", "t1_2")
        tiers["t1"] = [t1_1, t1_2]
        t2_1 = TieredPolicyId("t2", "t2_1")
        tiers["t2"] = [t2_1]
        ep.on_tiered_policy_update(tiers, async=True)
        self.step_actor(ep)

        self.assertEqual(
            self.m_ipt_gen.endpoint_updates.mock_calls,
            [
                mock.call(4, 'd', '1234', mac, ['prof1'],
                          OrderedDict([('t1', [TieredPolicyId('t1','t1_1'),
                                               TieredPolicyId('t1','t1_2')]),
                                       ('t2', [TieredPolicyId('t2','t2_1')])]))
            ])
Пример #18
0
    def test_on_interface_update_v6(self):
        combined_id = EndpointId("host_id", "orchestrator_id",
                                 "workload_id", "endpoint_id")
        ip_type = futils.IPV6
        retcode = futils.CommandOutput("", "")
        local_ep = self.get_local_endpoint(combined_id, ip_type)

        ips = ["1234::5678"]
        iface = "tapabcdef"
        data = { 'endpoint': "endpoint_id",
                 'mac': stub_utils.get_mac(),
                 'name': iface,
                 'ipv6_nets': ips,
                 'profile_ids': []}

        # We can only get on_interface_update calls after the first
        # on_endpoint_update, so trigger that.
        with mock.patch('calico.felix.devices.set_routes'):
            with mock.patch('calico.felix.devices.configure_interface_ipv6'):
                local_ep.on_endpoint_update(data, async=False)
                self.assertEqual(local_ep._mac, data['mac'])
                devices.configure_interface_ipv6.assert_called_once_with(iface,
                                                                         None)
                devices.set_routes.assert_called_once_with(ip_type,
                                                           set(ips),
                                                           iface,
                                                           data['mac'],
                                                           reset_arp=False)

        # Now pretend to get an interface update - does all the same work.
        with mock.patch('calico.felix.devices.set_routes'):
            with mock.patch('calico.felix.devices.configure_interface_ipv6'):
                local_ep.on_interface_update()
                devices.configure_interface_ipv6.assert_called_once_with(iface,
                                                                         None)
                devices.set_routes.assert_called_once_with(ip_type,
                                                           set(ips),
                                                           iface,
                                                           data['mac'],
                                                           reset_arp=False)
Пример #19
0
    def test_on_endpoint_update_v4(self):
        combined_id = EndpointId("host_id", "orchestrator_id",
                                 "workload_id", "endpoint_id")
        ip_type = futils.IPV4
        retcode = futils.CommandOutput("", "")
        local_ep = self.get_local_endpoint(combined_id, ip_type)

        # Call with no data; should be ignored (no configuration to remove).
        local_ep.on_endpoint_update(None, async=False)

        ips = ["1.2.3.4"]
        iface = "tapabcdef"
        data = { 'endpoint': "endpoint_id",
                 'mac': stub_utils.get_mac(),
                 'name': iface,
                 'ipv4_nets': ips,
                 'profile_ids': []}

        # Report an initial update (endpoint creation) and check configured
        with mock.patch('calico.felix.devices.set_routes'):
            with mock.patch('calico.felix.devices.configure_interface_ipv4'):
                local_ep.on_endpoint_update(data, async=False)
                self.assertEqual(local_ep._mac, data['mac'])
                devices.configure_interface_ipv4.assert_called_once_with(iface)
                devices.set_routes.assert_called_once_with(ip_type,
                                                           set(ips),
                                                           iface,
                                                           data['mac'],
                                                           reset_arp=True)

        # Send through an update with no changes - should redo without
        # resetting ARP.
        with mock.patch('calico.felix.devices.set_routes'):
            with mock.patch('calico.felix.devices.configure_interface_ipv4'):
                local_ep.on_endpoint_update(data, async=False)
                self.assertEqual(local_ep._mac, data['mac'])
                devices.configure_interface_ipv4.assert_called_once_with(iface)
                devices.set_routes.assert_called_once_with(ip_type,
                                                           set(ips),
                                                           iface,
                                                           data['mac'],
                                                           reset_arp=False)

        # Change the MAC address and try again, leading to reset of ARP.
        data['mac'] = stub_utils.get_mac()
        with mock.patch('calico.felix.devices.set_routes'):
            with mock.patch('calico.felix.devices.configure_interface_ipv4'):
                local_ep.on_endpoint_update(data, async=False)
                self.assertEqual(local_ep._mac, data['mac'])
                devices.configure_interface_ipv4.assert_called_once_with(iface)
                devices.set_routes.assert_called_once_with(ip_type,
                                                           set(ips),
                                                           iface,
                                                           data['mac'],
                                                           reset_arp=True)

        # Send empty data, which deletes the endpoint.
        with mock.patch('calico.felix.devices.set_routes'):
            local_ep.on_endpoint_update(None, async=False)
            devices.set_routes.assert_called_once_with(ip_type, set(),
                                                       data["name"], None)
Пример #20
0
    def test_on_endpoint_update_v6(self):
        combined_id = EndpointId("host_id", "orchestrator_id",
                                 "workload_id", "endpoint_id")
        ip_type = futils.IPV6
        retcode = futils.CommandOutput("", "")
        local_ep = self.get_local_endpoint(combined_id, ip_type)

        # Call with no data; should be ignored (no configuration to remove).
        local_ep.on_endpoint_update(None, async=False)

        ips = ["2001::abcd"]
        gway = "2020:ab::9876"
        iface = "tapabcdef"
        data = { 'endpoint': "endpoint_id",
                 'mac': stub_utils.get_mac(),
                 'name': iface,
                 'ipv6_nets': ips,
                 'ipv6_gateway': gway,
                 'profile_ids': []}

        # Report an initial update (endpoint creation) and check configured
        with mock.patch('calico.felix.devices.set_routes'):
            with mock.patch('calico.felix.devices.configure_interface_ipv6'):
                local_ep.on_endpoint_update(data, async=False)
                self.assertEqual(local_ep._mac, data['mac'])
                devices.configure_interface_ipv6.assert_called_once_with(iface,
                                                                         gway)
                devices.set_routes.assert_called_once_with(ip_type,
                                                           set(ips),
                                                           iface,
                                                           data['mac'],
                                                           reset_arp=False)

        # Send through an update with no changes - should redo without
        # resetting ARP.
        with mock.patch('calico.felix.devices.set_routes'):
            with mock.patch('calico.felix.devices.configure_interface_ipv6'):
                local_ep.on_endpoint_update(data, async=False)
                self.assertEqual(local_ep._mac, data['mac'])
                devices.configure_interface_ipv6.assert_called_once_with(iface,
                                                                         gway)
                devices.set_routes.assert_called_once_with(ip_type,
                                                           set(ips),
                                                           iface,
                                                           data['mac'],
                                                           reset_arp=False)

        # Send through an update with no changes - would reset ARP, but this is
        # IPv6 so it won't.
        data['mac'] = stub_utils.get_mac()
        with mock.patch('calico.felix.devices.set_routes'):
            with mock.patch('calico.felix.devices.configure_interface_ipv6'):
                local_ep.on_endpoint_update(data, async=False)
                self.assertEqual(local_ep._mac, data['mac'])
                devices.configure_interface_ipv6.assert_called_once_with(iface,
                                                                         gway)
                devices.set_routes.assert_called_once_with(ip_type,
                                                           set(ips),
                                                           iface,
                                                           data['mac'],
                                                           reset_arp=False)

        # Send empty data, which deletes the endpoint.
        with mock.patch('calico.felix.devices.set_routes'):
            local_ep.on_endpoint_update(None, async=False)
            devices.set_routes.assert_called_once_with(ip_type, set(),
                                                       data["name"], None)
Пример #21
0
    def test_main_flow(self):
        """
        Test starting up and going through some of the basic flow.
        """
        common.default_logging()
        context = stub_zmq.Context()
        agent = felix.FelixAgent(config_path, context)
        context.add_poll_result(0)
        agent.run()

        # Now we want to reply to the RESYNC request.
        resync_req = context.sent_data[TYPE_EP_REQ].pop()
        log.debug("Resync request : %s" % resync_req)
        self.assertFalse(context.sent_data_present())
        resync_id = resync_req['resync_id']
        resync_rsp = {
            'type': "RESYNCSTATE",
            'endpoint_count': 1,
            'rc': "SUCCESS",
            'message': "hello"
        }

        poll_result = context.add_poll_result(50)
        poll_result.add(TYPE_EP_REQ, resync_rsp)
        agent.run()

        # Felix expects one endpoint created message - give it what it wants
        endpoint_id = str(uuid.uuid4())
        log.debug("Build first endpoint created : %s" % endpoint_id)
        mac = stub_utils.get_mac()
        suffix = endpoint_id[:11]
        tap = "tap" + suffix
        addr = '1.2.3.4'
        endpoint_created_req = {
            'type': "ENDPOINTCREATED",
            'endpoint_id': endpoint_id,
            'resync_id': resync_id,
            'issued': futils.time_ms(),
            'mac': mac,
            'state': Endpoint.STATE_ENABLED,
            'addrs': [{
                'gateway': "1.2.3.1",
                'addr': addr
            }]
        }

        poll_result = context.add_poll_result(100)
        poll_result.add(TYPE_EP_REP, endpoint_created_req)
        agent.run()

        log.debug("Create tap interface %s" % tap)
        tap_obj = stub_devices.TapInterface(tap)
        stub_devices.add_tap(tap_obj)
        poll_result = context.add_poll_result(150)
        agent.run()

        #*********************************************************************#
        #* As soon as that endpoint has been made to exist, we should see an *#
        #* ACL request coming through, and a response to the endpoint        *#
        #* created.  We send a reply to that now.                            *#
        #*********************************************************************#
        endpoint_created_rsp = context.sent_data[TYPE_EP_REP].pop()
        self.assertEqual(endpoint_created_rsp['rc'], "SUCCESS")

        acl_req = context.sent_data[TYPE_ACL_REQ].pop()
        self.assertFalse(context.sent_data_present())
        self.assertEqual(acl_req['endpoint_id'], endpoint_id)

        acl_rsp = {'type': "GETACLSTATE", 'rc': "SUCCESS", 'message': ""}
        poll_result = context.add_poll_result(200)
        poll_result.add(TYPE_ACL_REQ, acl_rsp)

        # Check the rules are what we expect.
        set_expected_global_rules()
        add_endpoint_rules(suffix, tap, addr, None, mac)
        stub_fiptables.check_state(expected_iptables)
        add_endpoint_ipsets(suffix)
        stub_ipsets.check_state(expected_ipsets)

        # OK - now try giving it some ACLs, and see if they get applied correctly.
        acls = get_blank_acls()
        acls['v4']['outbound'].append({
            'cidr': "0.0.0.0/0",
            'protocol': "icmp"
        })
        acls['v4']['outbound'].append({
            'cidr': "1.2.3.0/24",
            'protocol': "tcp"
        })
        acls['v4']['outbound'].append({
            'cidr': "0.0.0.0/0",
            'protocol': "tcp",
            'port': "80"
        })
        acls['v4']['inbound'].append({
            'cidr': "1.2.2.0/24",
            'protocol': "icmp"
        })
        acls['v4']['inbound'].append({
            'cidr': "0.0.0.0/0",
            'protocol': "tcp",
            'port': "8080"
        })
        acls['v4']['inbound'].append({
            'cidr': "2.4.6.8/32",
            'protocol': "udp",
            'port': "8080"
        })
        acls['v4']['inbound'].append({'cidr': "1.2.3.3/32"})
        acls['v4']['inbound'].append({
            'cidr': "3.6.9.12/32",
            'protocol': "tcp",
            'port': ['10', '50']
        })

        acls['v4']['inbound'].append({
            'cidr': "5.4.3.2/32",
            'protocol': "icmp",
            'icmp_type': "3",
            'icmp_code': "2"
        })

        acls['v4']['inbound'].append({
            'cidr': "5.4.3.2/32",
            'protocol': "icmp",
            'icmp_type': "9"
        })

        acls['v4']['inbound'].append({
            'cidr': "5.4.3.2/32",
            'protocol': "icmp",
            'icmp_type': "blah"
        })

        # We include a couple of invalid rules that Felix will just ignore (and log).
        acls['v4']['inbound'].append({
            'cidr': "4.3.2.1/32",
            'protocol': "tcp",
            'port': ['blah', 'blah']
        })
        acls['v4']['inbound'].append({
            'cidr': "4.3.2.1/32",
            'protocol': "tcp",
            'port': ['1', '2', '3']
        })
        acls['v4']['inbound'].append({
            'cidr': "4.3.2.1/32",
            'protocol': "tcp",
            'port': 'flibble'
        })
        acls['v4']['inbound'].append({'protocol': "tcp"})
        acls['v4']['inbound'].append({'cidr': "4.3.2.1/32", 'port': "123"})
        acls['v4']['inbound'].append({
            'cidr': "4.3.2.1/32",
            'protocol': "icmp",
            'icmp_code': "blah"
        })
        acls['v4']['inbound'].append({
            'cidr': "4.3.2.1/32",
            'protocol': "icmp",
            'port': "1"
        })
        acls['v4']['inbound'].append({
            'cidr': "4.3.2.1/32",
            'protocol': "rsvp",
            'port': "1"
        })

        acl_req = {'type': "ACLUPDATE", 'acls': acls}

        poll_result.add(TYPE_ACL_SUB, acl_req, endpoint_id)
        agent.run()

        stub_fiptables.check_state(expected_iptables)
        expected_ipsets.add("felix-from-icmp-" + suffix, "0.0.0.0/1")
        expected_ipsets.add("felix-from-icmp-" + suffix, "128.0.0.0/1")
        expected_ipsets.add("felix-from-port-" + suffix, "1.2.3.0/24,tcp:0")
        expected_ipsets.add("felix-from-port-" + suffix, "0.0.0.0/1,tcp:80")
        expected_ipsets.add("felix-from-port-" + suffix, "128.0.0.0/1,tcp:80")

        expected_ipsets.add("felix-to-icmp-" + suffix, "1.2.2.0/24")
        expected_ipsets.add("felix-to-port-" + suffix, "0.0.0.0/1,tcp:8080")
        expected_ipsets.add("felix-to-port-" + suffix, "128.0.0.0/1,tcp:8080")
        expected_ipsets.add("felix-to-port-" + suffix, "2.4.6.8/32,udp:8080")
        expected_ipsets.add("felix-to-addr-" + suffix, "1.2.3.3/32")
        expected_ipsets.add("felix-to-port-" + suffix, "3.6.9.12/32,tcp:10-50")
        expected_ipsets.add("felix-to-port-" + suffix, "5.4.3.2/32,icmp:3/2")
        expected_ipsets.add("felix-to-port-" + suffix, "5.4.3.2/32,icmp:9/0")
        expected_ipsets.add("felix-to-port-" + suffix, "5.4.3.2/32,icmp:blah")

        stub_ipsets.check_state(expected_ipsets)

        # Add another endpoint, and check the state.
        endpoint_id2 = str(uuid.uuid4())
        log.debug("Build second endpoint created : %s" % endpoint_id2)
        mac2 = stub_utils.get_mac()
        suffix2 = endpoint_id2[:11]
        tap2 = "tap" + suffix2
        addr2 = '1.2.3.5'
        endpoint_created_req = {
            'type': "ENDPOINTCREATED",
            'endpoint_id': endpoint_id2,
            'issued': futils.time_ms(),
            'mac': mac2,
            'state': Endpoint.STATE_ENABLED,
            'addrs': [{
                'gateway': "1.2.3.1",
                'addr': addr2
            }]
        }

        poll_result = context.add_poll_result(250)
        poll_result.add(TYPE_EP_REP, endpoint_created_req)
        tap_obj2 = stub_devices.TapInterface(tap2)
        stub_devices.add_tap(tap_obj2)
        agent.run()

        # Check that we got what we expected - i.e. a success response, a GETACLSTATE,
        # and the rules in the right state.
        endpoint_created_rsp = context.sent_data[TYPE_EP_REP].pop()
        self.assertEqual(endpoint_created_rsp['rc'], "SUCCESS")

        acl_req = context.sent_data[TYPE_ACL_REQ].pop()
        self.assertEqual(acl_req['endpoint_id'], endpoint_id2)
        self.assertFalse(context.sent_data_present())

        add_endpoint_rules(suffix2, tap2, addr2, None, mac2)
        stub_fiptables.check_state(expected_iptables)
        add_endpoint_ipsets(suffix2)
        stub_ipsets.check_state(expected_ipsets)

        # OK, finally wind down with an ENDPOINTDESTROYED message for that second endpoint.
        endpoint_destroyed_req = {
            'type': "ENDPOINTDESTROYED",
            'endpoint_id': endpoint_id2,
            'issued': futils.time_ms()
        }

        poll_result = context.add_poll_result(300)
        poll_result.add(TYPE_EP_REP, endpoint_destroyed_req)
        stub_devices.del_tap(tap2)
        agent.run()

        # Rebuild and recheck the state.
        set_expected_global_rules()
        add_endpoint_rules(suffix, tap, addr, None, mac)
        stub_fiptables.check_state(expected_iptables)
Пример #22
0
    def test_resync(self):
        """
        Test the resync flows.
        """
        common.default_logging()
        context = stub_zmq.Context()
        agent = felix.FelixAgent(config_path, context)

        #*********************************************************************#
        #* Set the resync timeout to 5 seconds, and the KEEPALIVE timeout to *#
        #* much more.                                                        *#
        #*********************************************************************#
        agent.config.RESYNC_INT_SEC = 5
        agent.config.CONN_TIMEOUT_MS = 50000
        agent.config.CONN_KEEPALIVE_MS = 50000

        # Get started.
        context.add_poll_result(0)
        agent.run()

        # Now we should have got a resync request.
        resync_req = context.sent_data[TYPE_EP_REQ].pop()
        log.debug("Resync request : %s" % resync_req)
        self.assertFalse(context.sent_data_present())
        resync_id = resync_req['resync_id']
        resync_rsp = {
            'type': "RESYNCSTATE",
            'endpoint_count': "0",
            'rc': "SUCCESS",
            'message': "hello"
        }

        poll_result = context.add_poll_result(1000)
        poll_result.add(TYPE_EP_REQ, resync_rsp)
        agent.run()
        # nothing yet
        self.assertFalse(context.sent_data_present())

        poll_result = context.add_poll_result(5999)
        agent.run()
        # nothing yet - 4999 ms since last request
        self.assertFalse(context.sent_data_present())

        poll_result = context.add_poll_result(6001)
        agent.run()

        # We should have got another resync request.
        resync_req = context.sent_data[TYPE_EP_REQ].pop()
        log.debug("Resync request : %s" % resync_req)
        self.assertFalse(context.sent_data_present())
        resync_id = resync_req['resync_id']
        resync_rsp = {
            'type': "RESYNCSTATE",
            'endpoint_count': "2",
            'rc': "SUCCESS",
            'message': "hello"
        }

        # No more resyncs until enough data has arrived.
        poll_result = context.add_poll_result(15000)
        poll_result.add(TYPE_EP_REQ, resync_rsp)
        agent.run()
        self.assertFalse(context.sent_data_present())

        # Send an endpoint created message to Felix.
        endpoint_id = str(uuid.uuid4())
        log.debug("Build first endpoint created : %s" % endpoint_id)
        mac = stub_utils.get_mac()
        suffix = endpoint_id[:11]
        tap = "tap" + suffix
        addr = '1.2.3.4'
        endpoint_created_req = {
            'type': "ENDPOINTCREATED",
            'endpoint_id': endpoint_id,
            'resync_id': resync_id,
            'issued': futils.time_ms(),
            'mac': mac,
            'state': Endpoint.STATE_ENABLED,
            'addrs': [{
                'gateway': "1.2.3.1",
                'addr': addr
            }]
        }

        poll_result = context.add_poll_result(15001)
        poll_result.add(TYPE_EP_REP, endpoint_created_req)
        agent.run()

        # We stop using sent_data_present, since there are ACL requests around.
        endpoint_created_rsp = context.sent_data[TYPE_EP_REP].pop()
        self.assertEqual(endpoint_created_rsp['rc'], "SUCCESS")
        self.assertFalse(context.sent_data[TYPE_EP_REQ])

        # Send a second endpoint created message to Felix - triggers another resync.
        endpoint_id = str(uuid.uuid4())
        log.debug("Build second endpoint created : %s" % endpoint_id)
        mac = stub_utils.get_mac()
        suffix = endpoint_id[:11]
        tap = "tap" + suffix
        addr = '1.2.3.5'
        endpoint_created_req = {
            'type': "ENDPOINTCREATED",
            'endpoint_id': endpoint_id,
            'resync_id': resync_id,
            'issued': futils.time_ms(),
            'mac': mac,
            'state': Endpoint.STATE_ENABLED,
            'addrs': [{
                'gateway': "1.2.3.1",
                'addr': addr
            }]
        }

        poll_result = context.add_poll_result(15002)
        poll_result.add(TYPE_EP_REP, endpoint_created_req)
        agent.run()

        endpoint_created_rsp = context.sent_data[TYPE_EP_REP].pop()
        self.assertEqual(endpoint_created_rsp['rc'], "SUCCESS")
        self.assertFalse(context.sent_data[TYPE_EP_REQ])

        # No more resyncs until enough 5000 ms after last rsp.
        poll_result = context.add_poll_result(20000)
        poll_result.add(TYPE_EP_REQ, resync_rsp)
        agent.run()
        self.assertFalse(context.sent_data[TYPE_EP_REQ])

        # We should have got another resync request.
        poll_result = context.add_poll_result(20003)
        poll_result.add(TYPE_EP_REP, endpoint_created_req)
        agent.run()
        resync_req = context.sent_data[TYPE_EP_REQ].pop()
        log.debug("Resync request : %s" % resync_req)
        self.assertFalse(context.sent_data[TYPE_EP_REQ])
Пример #23
0
    def test_on_endpoint_update_v6(self):
        combined_id = EndpointId("host_id", "orchestrator_id",
                                 "workload_id", "endpoint_id")
        ip_type = futils.IPV6
        local_ep = self.get_local_endpoint(combined_id, ip_type)

        # Call with no data; should be ignored (no configuration to remove).
        local_ep.on_endpoint_update(None, async=True)
        self.step_actor(local_ep)

        ips = ["2001::abcd"]
        gway = "2020:ab::9876"
        iface = "tapabcdef"
        data = {
            'state': "active",
            'endpoint': "endpoint_id",
            'mac': stub_utils.get_mac(),
            'name': iface,
            'ipv6_nets': ips,
            'ipv6_gateway': gway,
            'profile_ids': ["prof1"]
        }

        # Report an initial update (endpoint creation) and check configured
        with nested(
                mock.patch('calico.felix.devices.set_routes'),
                mock.patch('calico.felix.devices.configure_interface_ipv6'),
                mock.patch('calico.felix.devices.interface_up'),
        ) as [m_set_routes, m_conf, m_iface_up]:
                m_iface_up.return_value = True
                local_ep.on_endpoint_update(data, async=True)
                self.step_actor(local_ep)
                self.assertEqual(local_ep._mac, data['mac'])
                m_conf.assert_called_once_with(iface, gway)
                m_set_routes.assert_called_once_with(ip_type,
                                                     set(ips),
                                                     iface,
                                                     data['mac'],
                                                     reset_arp=False)

        # Send through an update with no changes but a force update.  Should
        # force a re-write to iptables.
        with mock.patch('calico.felix.devices.set_routes') as m_set_routes:
            with mock.patch('calico.felix.devices.'
                            'configure_interface_ipv6') as m_conf:
                local_ep.on_endpoint_update(data, force_reprogram=True,
                                            async=True)
                self.step_actor(local_ep)
                self.assertEqual(local_ep._mac, data['mac'])
                self.assertTrue(m_conf.called)
                self.assertTrue(m_set_routes.called)

        # Send through an update with no changes - would reset ARP, but this is
        # IPv6 so it won't.
        data = data.copy()
        data['mac'] = stub_utils.get_mac()
        with mock.patch('calico.felix.devices.set_routes') as m_set_routes:
            with mock.patch('calico.felix.devices.'
                            'configure_interface_ipv6') as m_conf:
                local_ep.on_endpoint_update(data, async=True)
                self.step_actor(local_ep)
                self.assertEqual(local_ep._mac, data['mac'])
                m_conf.assert_called_once_with(iface, gway)
                m_set_routes.assert_called_once_with(ip_type,
                                                     set(ips),
                                                     iface,
                                                     data['mac'],
                                                     reset_arp=False)

        # Send empty data, which deletes the endpoint.
        with mock.patch('calico.felix.devices.set_routes') as m_set_routes:
            local_ep.on_endpoint_update(None, async=True)
            local_ep.on_unreferenced(async=True)
            self.step_actor(local_ep)
            m_set_routes.assert_called_once_with(ip_type, set(),
                                                 data["name"], None)
            self.assertRaises(AssertionError,
                              local_ep._finish_msg_batch, [], [])
            self.m_manager.on_object_cleanup_complete.assert_called_once_with(
                local_ep._id,
                local_ep,
                async=True,
            )
Пример #24
0
    def test_profile_id_update_triggers_iptables(self):
        combined_id = EndpointId("host_id", "orchestrator_id",
                                 "workload_id", "endpoint_id")
        ip_type = futils.IPV4
        local_ep = self.get_local_endpoint(combined_id, ip_type)

        ips = ["10.0.0.1"]
        iface = "tapabcdef"
        mac = stub_utils.get_mac()
        data = {'endpoint': "endpoint_id", 'mac': mac,
                'name': iface, 'ipv4_nets': ips, 'profile_ids': [],
                'state': "active"}
        local_ep._pending_endpoint = data.copy()

        # First update with endpoint not yet set, should trigger full sync.
        with mock.patch("calico.felix.devices.interface_up",
                        return_value=True):
            local_ep._apply_endpoint_update()
        self.assertEqual(local_ep.endpoint, data)
        self.assertFalse(local_ep._iptables_in_sync)
        self.assertFalse(local_ep._device_in_sync)

        local_ep._iptables_in_sync = True
        local_ep._device_in_sync = True

        # No-op update
        local_ep._pending_endpoint = data.copy()
        local_ep._apply_endpoint_update()
        self.assertTrue(local_ep._iptables_in_sync)
        self.assertTrue(local_ep._device_in_sync)

        # Set the state.
        local_ep._pending_endpoint = data.copy()
        local_ep._pending_endpoint["state"] = "inactive"
        local_ep._apply_endpoint_update()
        self.assertFalse(local_ep._iptables_in_sync)
        self.assertFalse(local_ep._device_in_sync)
        local_ep._device_in_sync = True
        local_ep._iptables_in_sync = True

        # Set the state back again...
        local_ep._pending_endpoint = data.copy()
        local_ep._pending_endpoint["state"] = "active"
        local_ep._apply_endpoint_update()
        self.assertFalse(local_ep._iptables_in_sync)
        self.assertFalse(local_ep._device_in_sync)
        local_ep._device_in_sync = True
        local_ep._iptables_in_sync = True

        # Profiles update.  Should update iptables.
        data = {'endpoint': "endpoint_id", 'mac': mac,
                'name': iface, 'ipv4_nets': ips, 'profile_ids': ["prof2"],
                "state": "active"}
        local_ep._pending_endpoint = data.copy()
        local_ep._apply_endpoint_update()
        self.assertFalse(local_ep._iptables_in_sync)
        local_ep._iptables_in_sync = True
        self.assertTrue(local_ep._device_in_sync)

        # IP update.  Should update routing.
        data = {'endpoint': "endpoint_id", 'mac': mac,
                'name': iface, 'ipv4_nets': ["10.0.0.2"],
                'profile_ids': ["prof2"],
                "state": "active"}
        local_ep._pending_endpoint = data.copy()
        local_ep._apply_endpoint_update()
        self.assertTrue(local_ep._iptables_in_sync)
        self.assertFalse(local_ep._device_in_sync)
        local_ep._device_in_sync = True

        # Delete, should update everything.
        local_ep._pending_endpoint = None
        local_ep._apply_endpoint_update()
        self.assertFalse(local_ep._iptables_in_sync)
        self.assertFalse(local_ep._device_in_sync)
Пример #25
0
    def test_on_interface_update_v6(self):
        combined_id = EndpointId("host_id", "orchestrator_id",
                                 "workload_id", "endpoint_id")
        ip_type = futils.IPV6
        local_ep = self.get_local_endpoint(combined_id, ip_type)

        ips = ["1234::5678"]
        iface = "tapabcdef"
        data = {
            'state': "active",
            'endpoint': "endpoint_id",
            'mac': stub_utils.get_mac(),
            'name': iface,
            'ipv6_nets': ips,
            'profile_ids': ["prof1"]
        }

        # We can only get on_interface_update calls after the first
        # on_endpoint_update, so trigger that.
        with nested(
                mock.patch('calico.felix.devices.set_routes'),
                mock.patch('calico.felix.devices.configure_interface_ipv6'),
                mock.patch('calico.felix.devices.interface_up'),
        ) as [m_set_routes, m_conf, m_iface_up]:
                m_iface_up.return_value = False
                local_ep.on_endpoint_update(data, async=True)
                self.step_actor(local_ep)
                self.assertEqual(local_ep._mac, data['mac'])
                self.assertFalse(m_conf.called)
                self.assertFalse(m_set_routes.called)
                self.assertFalse(local_ep._device_in_sync)

        # Now pretend to get an interface update - does all the same work.
        with mock.patch('calico.felix.devices.set_routes') as m_set_routes:
            with mock.patch('calico.felix.devices.'
                            'configure_interface_ipv6') as m_conf:
                local_ep.on_interface_update(True, async=True)
                self.step_actor(local_ep)
                m_conf.assert_called_once_with(iface, None)
                m_set_routes.assert_called_once_with(ip_type,
                                                     set(ips),
                                                     iface,
                                                     data['mac'],
                                                     reset_arp=False)
                self.assertTrue(local_ep._device_in_sync)

        # Now cover the error cases...
        with mock.patch('calico.felix.devices.'
                        'configure_interface_ipv6') as m_conf:
            with mock.patch('calico.felix.devices.'
                            'interface_exists') as ifce_exists:
                with mock.patch('calico.felix.devices.'
                                'interface_up') as ifce_up:
                    # Cycle through all the possibilities for the state.
                    ifce_exists.side_effect = [True, False, True]
                    ifce_up.side_effect = [True, False]
                    m_conf.side_effect = FailedSystemCall("", [], 1, "", "")
                    local_ep.on_interface_update(False, async=True)
                    self.step_actor(local_ep)
                    local_ep.on_interface_update(True, async=True)
                    self.step_actor(local_ep)
                    local_ep.on_interface_update(True, async=True)
                    self.step_actor(local_ep)
                    self.assertFalse(local_ep._device_in_sync)
Пример #26
0
    def test_on_endpoint_update_v6(self):
        combined_id = EndpointId("host_id", "orchestrator_id",
                                 "workload_id", "endpoint_id")
        ip_type = futils.IPV6
        local_ep = self.get_local_endpoint(combined_id, ip_type)

        # Call with no data; should be ignored (no configuration to remove).
        local_ep.on_endpoint_update(None, async=True)
        self.step_actor(local_ep)

        ips = ["2001::abcd"]
        gway = "2020:ab::9876"
        iface = "tapabcdef"
        data = {
            'state': "active",
            'endpoint': "endpoint_id",
            'mac': stub_utils.get_mac(),
            'name': iface,
            'ipv6_nets': ips,
            'ipv6_gateway': gway,
            'profile_ids': ["prof1"]
        }

        # Report an initial update (endpoint creation) and check configured
        with nested(
                mock.patch('calico.felix.devices.set_routes'),
                mock.patch('calico.felix.devices.configure_interface_ipv6'),
                mock.patch('calico.felix.devices.interface_exists'),
                mock.patch('calico.felix.devices.interface_up'),
        ) as [m_set_routes, m_conf, m_iface_exists, m_iface_up]:
                m_iface_exists.return_value = True
                m_iface_up.return_value = True
                local_ep.on_endpoint_update(data, async=True)
                self.step_actor(local_ep)
                self.assertEqual(local_ep._mac, data['mac'])
                m_conf.assert_called_once_with(iface, gway)
                m_set_routes.assert_called_once_with(ip_type,
                                                     set(ips),
                                                     iface,
                                                     data['mac'],
                                                     reset_arp=False)

        # Send through an update with no changes but a force update.  Should
        # force a re-write to iptables.
        with mock.patch('calico.felix.devices.set_routes') as m_set_routes:
            with mock.patch('calico.felix.devices.'
                            'configure_interface_ipv6') as m_conf:
                local_ep.on_endpoint_update(data, force_reprogram=True,
                                            async=True)
                self.step_actor(local_ep)
                self.assertEqual(local_ep._mac, data['mac'])
                self.assertTrue(m_conf.called)
                self.assertTrue(m_set_routes.called)

        # Send through an update with no changes - would reset ARP, but this is
        # IPv6 so it won't.
        data = data.copy()
        data['mac'] = stub_utils.get_mac()
        with mock.patch('calico.felix.devices.set_routes') as m_set_routes:
            with mock.patch('calico.felix.devices.'
                            'configure_interface_ipv6') as m_conf:
                local_ep.on_endpoint_update(data, async=True)
                self.step_actor(local_ep)
                self.assertEqual(local_ep._mac, data['mac'])
                m_conf.assert_called_once_with(iface, gway)
                m_set_routes.assert_called_once_with(ip_type,
                                                     set(ips),
                                                     iface,
                                                     data['mac'],
                                                     reset_arp=False)

        # Send empty data, which deletes the endpoint.
        with mock.patch('calico.felix.devices.set_routes') as m_set_routes:
            local_ep.on_endpoint_update(None, async=True)
            local_ep.on_unreferenced(async=True)
            self.step_actor(local_ep)
            m_set_routes.assert_called_once_with(ip_type, set(),
                                                 data["name"], None)
            local_ep._finish_msg_batch([], [])  # Should be ignored
            self.m_manager.on_object_cleanup_complete.assert_called_once_with(
                local_ep._id,
                local_ep,
                async=True,
            )
Пример #27
0
    def test_on_endpoint_update_v4(self):
        combined_id = EndpointId("host_id", "orchestrator_id",
                                 "workload_id", "endpoint_id")
        ip_type = futils.IPV4
        local_ep = self.get_local_endpoint(combined_id, ip_type)

        # Call with no data; should be ignored (no configuration to remove).
        local_ep.on_endpoint_update(None, async=True)
        self.step_actor(local_ep)

        ips = ["1.2.3.4"]
        iface = "tapabcdef"
        data = {
            'state': "active",
            'endpoint': "endpoint_id",
            'mac': stub_utils.get_mac(),
            'name': iface,
            'ipv4_nets': ips,
            'profile_ids': ["prof1"]
        }

        # Report an initial update (endpoint creation) and check configured
        with nested(
                mock.patch('calico.felix.devices.set_routes'),
                mock.patch('calico.felix.devices.configure_interface_ipv4'),
                mock.patch('calico.felix.devices.interface_exists'),
                mock.patch('calico.felix.devices.interface_up'),
        ) as [m_set_routes, m_conf, m_iface_exists, m_iface_up]:
            m_iface_exists.return_value = True
            m_iface_up.return_value = True

            local_ep.on_endpoint_update(data, async=True)
            self.step_actor(local_ep)

            self.assertEqual(local_ep._mac, data['mac'])
            m_conf.assert_called_once_with(iface)
            m_set_routes.assert_called_once_with(ip_type,
                                                 set(ips),
                                                 iface,
                                                 data['mac'],
                                                 reset_arp=True)

        # Send through an update with no changes - should be a no-op.
        with mock.patch('calico.felix.devices.set_routes') as m_set_routes:
            with mock.patch('calico.felix.devices.'
                            'configure_interface_ipv4') as m_conf:
                local_ep.on_endpoint_update(data, async=True)
                self.step_actor(local_ep)
                self.assertEqual(local_ep._mac, data['mac'])
                self.assertFalse(m_conf.called)
                self.assertFalse(m_set_routes.called)

        # Change the MAC address and try again, leading to reset of ARP
        data = data.copy()
        data['mac'] = stub_utils.get_mac()
        with mock.patch('calico.felix.devices.set_routes') as m_set_routes:
            with mock.patch('calico.felix.devices.'
                            'configure_interface_ipv4') as m_conf:
                local_ep.on_endpoint_update(data, async=True)
                self.step_actor(local_ep)
                self.assertEqual(local_ep._mac, data['mac'])
                m_conf.assert_called_once_with(iface)
                m_set_routes.assert_called_once_with(ip_type,
                                                     set(ips),
                                                     iface,
                                                     data['mac'],
                                                     reset_arp=True)

        # Send empty data, which deletes the endpoint.
        with mock.patch('calico.felix.devices.set_routes') as m_set_routes:
            local_ep.on_endpoint_update(None, async=True)
            self.step_actor(local_ep)
            m_set_routes.assert_called_once_with(ip_type, set(),
                                                 data["name"], None)
Пример #28
0
    def test_on_interface_update_v6(self):
        combined_id = EndpointId("host_id", "orchestrator_id",
                                 "workload_id", "endpoint_id")
        ip_type = futils.IPV6
        local_ep = self.get_local_endpoint(combined_id, ip_type)

        ips = ["1234::5678"]
        iface = "tapabcdef"
        data = {
            'state': "active",
            'endpoint': "endpoint_id",
            'mac': stub_utils.get_mac(),
            'name': iface,
            'ipv6_nets': ips,
            'profile_ids': ["prof1"]
        }

        # We can only get on_interface_update calls after the first
        # on_endpoint_update, so trigger that.
        with nested(
                mock.patch('calico.felix.devices.set_routes'),
                mock.patch('calico.felix.devices.configure_interface_ipv6'),
                mock.patch('calico.felix.devices.interface_up'),
        ) as [m_set_routes, m_conf, m_iface_up]:
                m_iface_up.return_value = False
                local_ep.on_endpoint_update(data, async=True)
                self.step_actor(local_ep)
                self.assertEqual(local_ep._mac, data['mac'])
                m_conf.assert_called_once_with(iface, None)
                m_set_routes.assert_called_once_with(ip_type,
                                                     set(ips),
                                                     iface,
                                                     data['mac'],
                                                     reset_arp=False)

        # Now pretend to get an interface update - does all the same work.
        with mock.patch('calico.felix.devices.set_routes') as m_set_routes:
            with mock.patch('calico.felix.devices.'
                            'configure_interface_ipv6') as m_conf:
                local_ep.on_interface_update(True, async=True)
                self.step_actor(local_ep)
                m_conf.assert_called_once_with(iface, None)
                m_set_routes.assert_called_once_with(ip_type,
                                                     set(ips),
                                                     iface,
                                                     data['mac'],
                                                     reset_arp=False)
                self.assertTrue(local_ep._device_in_sync)

        # Now cover the error cases...
        with mock.patch('calico.felix.devices.'
                        'configure_interface_ipv6') as m_conf:
            with mock.patch('calico.felix.devices.'
                            'interface_exists') as ifce_exists:
                with mock.patch('calico.felix.devices.'
                                'interface_up') as ifce_up:
                    # Cycle through all the possibilities for the state.
                    ifce_exists.side_effect = [True, False, True]
                    ifce_up.side_effect = [True, False]
                    m_conf.side_effect = FailedSystemCall("", [], 1, "", "")
                    local_ep.on_interface_update(False, async=True)
                    self.step_actor(local_ep)
                    local_ep.on_interface_update(True, async=True)
                    self.step_actor(local_ep)
                    local_ep.on_interface_update(True, async=True)
                    self.step_actor(local_ep)
                    self.assertFalse(local_ep._device_in_sync)
Пример #29
0
    def test_profile_id_update_triggers_iptables(self):
        combined_id = EndpointId("host_id", "orchestrator_id",
                                 "workload_id", "endpoint_id")
        ip_type = futils.IPV4
        local_ep = self.get_local_endpoint(combined_id, ip_type)

        ips = ["10.0.0.1"]
        iface = "tapabcdef"
        mac = stub_utils.get_mac()
        data = {'endpoint': "endpoint_id", 'mac': mac,
                'name': iface, 'ipv4_nets': ips, 'profile_ids': [],
                'state': "active"}
        local_ep._pending_endpoint = data.copy()

        # First update with endpoint not yet set, should trigger full sync.
        with mock.patch("calico.felix.devices.interface_up",
                        return_value=True):
            local_ep._apply_endpoint_update()
        self.assertEqual(local_ep.endpoint, data)
        self.assertFalse(local_ep._iptables_in_sync)
        self.assertFalse(local_ep._device_in_sync)

        local_ep._iptables_in_sync = True
        local_ep._device_in_sync = True

        # No-op update
        local_ep._pending_endpoint = data.copy()
        local_ep._apply_endpoint_update()
        self.assertTrue(local_ep._iptables_in_sync)
        self.assertTrue(local_ep._device_in_sync)

        # Set the state.
        local_ep._pending_endpoint = data.copy()
        local_ep._pending_endpoint["state"] = "inactive"
        local_ep._apply_endpoint_update()
        self.assertFalse(local_ep._iptables_in_sync)
        self.assertFalse(local_ep._device_in_sync)
        local_ep._device_in_sync = True
        local_ep._iptables_in_sync = True

        # Set the state back again...
        local_ep._pending_endpoint = data.copy()
        local_ep._pending_endpoint["state"] = "active"
        local_ep._apply_endpoint_update()
        self.assertFalse(local_ep._iptables_in_sync)
        self.assertFalse(local_ep._device_in_sync)
        local_ep._device_in_sync = True
        local_ep._iptables_in_sync = True

        # Profiles update.  Should update iptables.
        data = {'endpoint': "endpoint_id", 'mac': mac,
                'name': iface, 'ipv4_nets': ips, 'profile_ids': ["prof2"],
                "state": "active"}
        local_ep._pending_endpoint = data.copy()
        local_ep._apply_endpoint_update()
        self.assertFalse(local_ep._iptables_in_sync)
        local_ep._iptables_in_sync = True
        self.assertTrue(local_ep._device_in_sync)

        # IP update.  Should update routing.
        data = {'endpoint': "endpoint_id", 'mac': mac,
                'name': iface, 'ipv4_nets': ["10.0.0.2"],
                'profile_ids': ["prof2"],
                "state": "active"}
        local_ep._pending_endpoint = data.copy()
        local_ep._apply_endpoint_update()
        self.assertTrue(local_ep._iptables_in_sync)
        self.assertFalse(local_ep._device_in_sync)
        local_ep._device_in_sync = True

        # Delete, should update everything.
        local_ep._pending_endpoint = None
        local_ep._apply_endpoint_update()
        self.assertFalse(local_ep._iptables_in_sync)
        self.assertFalse(local_ep._device_in_sync)
Пример #30
0
    def test_on_endpoint_update_v4(self):
        combined_id = EndpointId("host_id", "orchestrator_id",
                                 "workload_id", "endpoint_id")
        ip_type = futils.IPV4
        local_ep = self.get_local_endpoint(combined_id, ip_type)

        # Call with no data; should be ignored (no configuration to remove).
        local_ep.on_endpoint_update(None, async=True)
        self.step_actor(local_ep)

        ips = ["1.2.3.4"]
        iface = "tapabcdef"
        data = {
            'state': "active",
            'endpoint': "endpoint_id",
            'mac': stub_utils.get_mac(),
            'name': iface,
            'ipv4_nets': ips,
            'profile_ids': ["prof1"]
        }

        # Report an initial update (endpoint creation) and check configured
        with nested(
                mock.patch('calico.felix.devices.set_routes'),
                mock.patch('calico.felix.devices.configure_interface_ipv4'),
                mock.patch('calico.felix.devices.interface_up'),
        ) as [m_set_routes, m_conf, m_iface_up]:
            m_iface_up.return_value = True
            local_ep.on_endpoint_update(data, async=True)
            self.step_actor(local_ep)
            self.assertEqual(local_ep._mac, data['mac'])
            m_conf.assert_called_once_with(iface)
            m_set_routes.assert_called_once_with(ip_type,
                                                 set(ips),
                                                 iface,
                                                 data['mac'],
                                                 reset_arp=True)

        # Send through an update with no changes - should be a no-op.
        with mock.patch('calico.felix.devices.set_routes') as m_set_routes:
            with mock.patch('calico.felix.devices.'
                            'configure_interface_ipv4') as m_conf:
                local_ep.on_endpoint_update(data, async=True)
                self.step_actor(local_ep)
                self.assertEqual(local_ep._mac, data['mac'])
                self.assertFalse(m_conf.called)
                self.assertFalse(m_set_routes.called)

        # Change the MAC address and try again, leading to reset of ARP
        data = data.copy()
        data['mac'] = stub_utils.get_mac()
        with mock.patch('calico.felix.devices.set_routes') as m_set_routes:
            with mock.patch('calico.felix.devices.'
                            'configure_interface_ipv4') as m_conf:
                local_ep.on_endpoint_update(data, async=True)
                self.step_actor(local_ep)
                self.assertEqual(local_ep._mac, data['mac'])
                m_conf.assert_called_once_with(iface)
                m_set_routes.assert_called_once_with(ip_type,
                                                     set(ips),
                                                     iface,
                                                     data['mac'],
                                                     reset_arp=True)

        # Send empty data, which deletes the endpoint.
        with mock.patch('calico.felix.devices.set_routes') as m_set_routes:
            local_ep.on_endpoint_update(None, async=True)
            self.step_actor(local_ep)
            m_set_routes.assert_called_once_with(ip_type, set(),
                                                 data["name"], None)
Пример #31
0
    def test_on_endpoint_update_v4(self):
        combined_id = EndpointId("host_id", "orchestrator_id",
                                 "workload_id", "endpoint_id")
        ip_type = futils.IPV4
        local_ep = self.get_local_endpoint(combined_id, ip_type)

        # Call with no data; should be ignored (no configuration to remove).
        local_ep.on_endpoint_update(None, async=True)
        self.step_actor(local_ep)

        ips = ["1.2.3.4/32"]
        iface = "tapabcdef"
        data = {
            'state': "active",
            'endpoint': "endpoint_id",
            'mac': stub_utils.get_mac(),
            'name': iface,
            'ipv4_nets': ips,
            'profile_ids': ["prof1"]
        }

        # Report an initial update (endpoint creation) and check configured
        with mock.patch('calico.felix.devices.remove_conntrack_flows') as m_rem_conntrack,\
                mock.patch('calico.felix.devices.set_routes') as m_set_routes,\
                mock.patch('calico.felix.devices.configure_interface_ipv4') as m_conf,\
                mock.patch('calico.felix.devices.interface_exists') as m_iface_exists,\
                mock.patch('calico.felix.devices.interface_up') as m_iface_up:
            m_iface_exists.return_value = True
            m_iface_up.return_value = True

            local_ep.on_endpoint_update(data, async=True)
            self.step_actor(local_ep)

            self.assertEqual(local_ep._mac, data['mac'])
            m_conf.assert_called_once_with(iface)
            m_set_routes.assert_called_once_with(ip_type,
                                                 set(["1.2.3.4"]),
                                                 iface,
                                                 data['mac'],
                                                 reset_arp=True)
            self.assertFalse(m_rem_conntrack.called)

        # Send through an update with no changes - should be a no-op.
        with mock.patch('calico.felix.devices.remove_conntrack_flows') as m_rem_conntrack,\
                mock.patch('calico.felix.devices.set_routes') as m_set_routes,\
                mock.patch('calico.felix.devices.configure_interface_ipv4') as m_conf:
            local_ep.on_endpoint_update(data, async=True)
            self.step_actor(local_ep)
            self.assertEqual(local_ep._mac, data['mac'])
            self.assertFalse(m_conf.called)
            self.assertFalse(m_set_routes.called)
            self.assertFalse(m_rem_conntrack.called)

        # Change the MAC address and try again, leading to reset of ARP
        data = data.copy()
        data['mac'] = stub_utils.get_mac()
        with mock.patch('calico.felix.devices.set_routes') as m_set_routes:
            with mock.patch('calico.felix.devices.'
                            'configure_interface_ipv4') as m_conf:
                local_ep.on_endpoint_update(data, async=True)
                self.step_actor(local_ep)
                self.assertEqual(local_ep._mac, data['mac'])
                m_conf.assert_called_once_with(iface)
                m_set_routes.assert_called_once_with(ip_type,
                                                     set(["1.2.3.4"]),
                                                     iface,
                                                     data['mac'],
                                                     reset_arp=True)

        # Change the IP address, causing an iptables and route refresh.
        data = data.copy()
        data["ipv4_nets"] = ["1.2.3.5"]
        with mock.patch('calico.felix.devices.set_routes') as m_set_routes,\
                mock.patch('calico.felix.devices.configure_interface_ipv4') as _m_conf,\
                mock.patch('calico.felix.endpoint.LocalEndpoint._update_chains') as _m_up_c,\
                mock.patch('calico.felix.devices.remove_conntrack_flows') as m_rem_conntrack:
            local_ep.on_endpoint_update(data, async=True)
            self.step_actor(local_ep)
            m_set_routes.assert_called_once_with(ip_type,
                                                 set(["1.2.3.5"]),
                                                 iface,
                                                 data['mac'],
                                                 reset_arp=True)
            self.assertFalse(local_ep._update_chains.called)
            m_rem_conntrack.assert_called_once_with(set(["1.2.3.4"]), 4)

        # Change the nat mappings, causing an iptables and route refresh.
        data = data.copy()
        data['ipv4_nat'] = [
            {
                'int_ip': '1.2.3.4',
                'ext_ip': '5.6.7.8'
            }
        ]
        with mock.patch('calico.felix.devices.set_routes') as m_set_routes,\
                mock.patch('calico.felix.devices.configure_interface_ipv4') as _m_conf,\
                mock.patch('calico.felix.endpoint.LocalEndpoint._update_chains') as _m_up_c,\
                mock.patch('calico.felix.devices.remove_conntrack_flows') as m_rem_conntrack:
            local_ep.on_endpoint_update(data, async=True)
            self.step_actor(local_ep)
            m_set_routes.assert_called_once_with(ip_type,
                                                 set(["1.2.3.5", "5.6.7.8"]),
                                                 iface,
                                                 data['mac'],
                                                 reset_arp=True)
            local_ep._update_chains.assert_called_once_with()
            self.assertFalse(m_rem_conntrack.called)

        # Send empty data, which deletes the endpoint.
        with mock.patch('calico.felix.devices.set_routes') as m_set_routes,\
               mock.patch('calico.felix.devices.remove_conntrack_flows') as m_rem_conntrack:
            local_ep.on_endpoint_update(None, async=True)
            self.step_actor(local_ep)
            m_set_routes.assert_called_once_with(ip_type, set(),
                                                 data["name"], None)
            # Should clean up conntrack entries for all IPs.
            m_rem_conntrack.assert_called_once_with(
                set(['1.2.3.5', '5.6.7.8']), 4
            )
Пример #32
0
    def test_on_endpoint_update_v6(self):
        combined_id = EndpointId("host_id", "orchestrator_id",
                                 "workload_id", "endpoint_id")
        ip_type = futils.IPV6
        local_ep = self.get_local_endpoint(combined_id, ip_type)

        # Call with no data; should be ignored (no configuration to remove).
        local_ep.on_endpoint_update(None, async=True)
        self.step_actor(local_ep)

        nets = ["2001::abcd/128"]
        gway = "2020:ab::9876"
        iface = "tapabcdef"
        data = {
            'state': "active",
            'endpoint': "endpoint_id",
            'mac': stub_utils.get_mac(),
            'name': iface,
            'ipv6_nets': nets,
            'ipv6_gateway': gway,
            'profile_ids': ["prof1"]
        }

        # Report an initial update (endpoint creation) and check configured
        with mock.patch('calico.felix.devices.set_routes') as m_set_routes,\
                mock.patch('calico.felix.devices.configure_interface_ipv6') as m_conf,\
                mock.patch('calico.felix.devices.interface_exists') as m_iface_exists,\
                mock.patch('calico.felix.devices.interface_up') as m_iface_up, \
                mock.patch('calico.felix.devices.remove_conntrack_flows') as m_rem_conntrack:
            m_iface_exists.return_value = True
            m_iface_up.return_value = True
            local_ep.on_endpoint_update(data, async=True)
            self.step_actor(local_ep)
            self.assertEqual(local_ep._mac, data['mac'])
            m_conf.assert_called_once_with(iface, gway)
            m_set_routes.assert_called_once_with(ip_type,
                                                 set(["2001::abcd"]),
                                                 iface,
                                                 data['mac'],
                                                 reset_arp=False)
            self.assertFalse(m_rem_conntrack.called)

        # Send through an update with no changes but a force update.  Should
        # force a re-write to iptables.
        with mock.patch('calico.felix.devices.set_routes') as m_set_routes:
            with mock.patch('calico.felix.devices.'
                            'configure_interface_ipv6') as m_conf:
                local_ep.on_endpoint_update(data, force_reprogram=True,
                                            async=True)
                self.step_actor(local_ep)
                self.assertEqual(local_ep._mac, data['mac'])
                self.assertTrue(m_conf.called)
                self.assertTrue(m_set_routes.called)

        # Send through an update with no changes - would reset ARP, but this is
        # IPv6 so it won't.
        data = data.copy()
        data['mac'] = stub_utils.get_mac()
        with mock.patch('calico.felix.devices.set_routes') as m_set_routes:
            with mock.patch('calico.felix.devices.'
                            'configure_interface_ipv6') as m_conf:
                local_ep.on_endpoint_update(data, async=True)
                self.step_actor(local_ep)
                self.assertEqual(local_ep._mac, data['mac'])
                m_conf.assert_called_once_with(iface, gway)
                m_set_routes.assert_called_once_with(ip_type,
                                                     set(["2001::abcd"]),
                                                     iface,
                                                     data['mac'],
                                                     reset_arp=False)

        # Change the nat mappings, causing an iptables and route refresh.
        data = data.copy()
        nets.append('2001::abce/128')
        data['ipv6_nat'] = [
            {
                'int_ip': '2001::abcd',
                'ext_ip': '2001::abce'
            }
        ]
        with mock.patch('calico.felix.devices.set_routes') as m_set_routes,\
                mock.patch('calico.felix.devices.configure_interface_ipv6') as m_conf,\
                mock.patch('calico.felix.endpoint.LocalEndpoint._update_chains') as _m_up_c:
            local_ep.on_endpoint_update(data, async=True)
            self.step_actor(local_ep)
            m_set_routes.assert_called_once_with(
                ip_type,
                set(["2001::abcd", "2001::abce"]),
                iface,
                data['mac'],
                reset_arp=False
            )
            local_ep._update_chains.assert_called_once_with()

        # Send empty data, which deletes the endpoint.
        with mock.patch('calico.felix.devices.set_routes') as m_set_routes,\
                mock.patch('calico.felix.devices.remove_conntrack_flows') as m_rem_conntrack:
            local_ep.on_endpoint_update(None, async=True)
            local_ep.on_unreferenced(async=True)
            self.step_actor(local_ep)
            m_set_routes.assert_called_once_with(ip_type, set(),
                                                 data["name"], None)
            local_ep._finish_msg_batch([], [])  # Should be ignored
            self.m_manager.on_object_cleanup_complete.assert_called_once_with(
                local_ep._id,
                local_ep,
                async=True,
            )
            m_rem_conntrack.assert_called_once_with(set(['2001::abcd',
                                                         '2001::abce']), 6)