예제 #1
0
    def test_initial_snapshot(self):
        # Create the DHCP agent.
        agent = CalicoDhcpAgent()

        # Check that running it invokes the etcd watcher loop.
        with mock.patch.object(agent, 'etcd') as etcdobj:
            agent.run()
            etcdobj.start.assert_called_with()

        with mock.patch.object(agent, 'call_driver') as call_driver:
            # Notify a non-empty initial snapshot.
            snapshot_data = agent.etcd._pre_snapshot_hook()
            agent.etcd.on_endpoint_set(
                EtcdResponse(value=json.dumps({
                    'spec': {
                        'interfaceName': 'tap1234',
                        'mac': 'fe:16:65:12:33:44',
                        'profiles': ['profile-1'],
                        'ipNetworks': ['10.28.0.2/32'],
                        'ipv4Gateway': '10.28.0.1',
                    }
                })), make_endpoint_name('endpoint-4'))
            agent.etcd._post_snapshot_hook(snapshot_data)

            # Check DHCP driver was not troubled - because the subnet data was
            # missing and so the port could not be processed further.
            call_driver.assert_not_called()
    def test_initial_snapshot(self, etcd_client_cls):
        # Create the DHCP agent.
        agent = CalicoDhcpAgent()
        etcd_client = etcd_client_cls.return_value

        # Check that running it invokes the etcd watcher loop.
        with mock.patch.object(agent, 'etcd') as etcdobj:
            agent.run()
            etcdobj.loop.assert_called_with()

        # Arrange for subnet read to fail.
        etcd_client.read.side_effect = etcd.EtcdKeyNotFound

        with mock.patch.object(agent, 'call_driver') as call_driver:
            # Notify a non-empty initial snapshot.
            etcd_snapshot_node = mock.Mock()
            etcd_snapshot_node.action = 'exist'
            etcd_snapshot_node.key = ("/calico/v1/host/" +
                                      socket.gethostname() +
                                      "/workload/openstack" +
                                      "/workload_id/endpoint/endpoint-4")
            etcd_snapshot_node.value = json.dumps({
                'state':
                'active',
                'name':
                'tap1234',
                'mac':
                'fe:16:65:12:33:44',
                'profile_ids': ['profile-1'],
                'ipv4_nets': ['10.28.0.2/32'],
                'ipv4_subnet_ids': ['v4subnet-4'],
                'ipv4_gateway':
                '10.28.0.1',
                'ipv6_nets': [],
                'ipv6_subnet_ids': []
            })
            etcd_snapshot_response = mock.Mock()
            etcd_snapshot_response.leaves = [etcd_snapshot_node]
            agent.etcd._on_snapshot_loaded(etcd_snapshot_response)

            # Check expected subnet was read from etcd.
            etcd_client.read.assert_has_calls([
                mock.call(datamodel_v1.key_for_subnet('v4subnet-4'),
                          consistent=True)
            ])
            etcd_client.read.reset_mock()

            # Check DHCP driver was not troubled - because the subnet data was
            # missing and so the port could not be processed further.
            call_driver.assert_not_called()
    def test_initial_snapshot(self, etcd_client_cls):
        # Create the DHCP agent.
        agent = CalicoDhcpAgent()
        etcd_client = etcd_client_cls.return_value

        # Check that running it invokes the etcd watcher loop.
        with mock.patch.object(agent, 'etcd') as etcdobj:
            agent.run()
            etcdobj.loop.assert_called_with()

        # Arrange for subnet read to fail.
        etcd_client.read.side_effect = etcd.EtcdKeyNotFound

        with mock.patch.object(agent, 'call_driver') as call_driver:
            # Notify a non-empty initial snapshot.
            etcd_snapshot_node = mock.Mock()
            etcd_snapshot_node.action = 'exist'
            etcd_snapshot_node.key = ("/calico/v1/host/" +
                                      socket.gethostname() +
                                      "/workload/openstack" +
                                      "/workload_id/endpoint/endpoint-4")
            etcd_snapshot_node.value = json.dumps({
                'state': 'active',
                'name': 'tap1234',
                'mac': 'fe:16:65:12:33:44',
                'profile_ids': ['profile-1'],
                'ipv4_nets': ['10.28.0.2/32'],
                'ipv4_subnet_ids': ['v4subnet-4'],
                'ipv4_gateway': '10.28.0.1',
                'ipv6_nets': [],
                'ipv6_subnet_ids': []
            })
            etcd_snapshot_response = mock.Mock()
            etcd_snapshot_response.leaves = [etcd_snapshot_node]
            agent.etcd._on_snapshot_loaded(etcd_snapshot_response)

            # Check expected subnet was read from etcd.
            etcd_client.read.assert_has_calls([
                mock.call(datamodel_v1.key_for_subnet('v4subnet-4'),
                          consistent=True)
            ])
            etcd_client.read.reset_mock()

            # Check DHCP driver was not troubled - because the subnet data was
            # missing and so the port could not be processed further.
            call_driver.assert_not_called()
    def test_mainline(self, etcd_client_cls):
        # Create the DHCP agent.
        agent = CalicoDhcpAgent()
        etcd_client = etcd_client_cls.return_value

        # Check that running it invokes the etcd watcher loop.
        with mock.patch.object(agent, 'etcd') as etcdobj:
            agent.run()
            etcdobj.loop.assert_called_with()

        # Notify initial snapshot (empty).
        with mock.patch.object(agent, 'call_driver') as call_driver:
            etcd_snapshot_response = mock.Mock()
            etcd_snapshot_response.leaves = []
            agent.etcd._on_snapshot_loaded(etcd_snapshot_response)
            call_driver.assert_not_called()

        # Prepare subnet reads for the endpoints that we will notify.
        self.first_workload_read = True

        def etcd_client_read(key, **kwargs):
            LOG.info('etcd_client_read %s %s', key, kwargs)
            if 'v4subnet-1' in key:
                self.assertEqual('/calico/dhcp/v1/subnet/v4subnet-1', key)
                return EtcdResponse(value=json.dumps({
                    'cidr': '10.28.0.0/24',
                    'gateway_ip': '10.28.0.1',
                    'host_routes': []
                }))
            if 'v6subnet-1' in key:
                return EtcdResponse(
                    value=json.dumps({
                        'cidr': '2001:db8:1::/80',
                        'gateway_ip': '2001:db8:1::1'
                    }))
            if 'v4subnet-2' in key:
                return EtcdResponse(value=json.dumps({
                    'cidr':
                    '10.29.0.0/24',
                    'gateway_ip':
                    '10.29.0.1',
                    'host_routes': [{
                        'destination': '11.11.0.0/16',
                        'nexthop': '10.65.0.1'
                    }]
                }))
            if key == '/calico/v1/host/nj-ubuntu/workload':
                if self.first_workload_read:
                    # This is the recursive read that the CalicoEtcdWatcher
                    # loop makes after we've triggered it to resync.
                    etcd_snapshot_node = mock.Mock()
                    etcd_snapshot_node.action = 'exist'
                    etcd_snapshot_node.key = (
                        "/calico/v1/host/" + socket.gethostname() +
                        "/workload/openstack" +
                        "/workload_id/endpoint/endpoint-4")
                    etcd_snapshot_node.value = json.dumps({
                        'state':
                        'active',
                        'name':
                        'tap1234',
                        'mac':
                        'fe:16:65:12:33:44',
                        'profile_ids': ['profile-1'],
                        'ipv4_nets': ['10.28.0.2/32'],
                        'ipv4_subnet_ids': ['v4subnet-1'],
                        'ipv4_gateway':
                        '10.28.0.1',
                        'ipv6_nets': [],
                        'ipv6_subnet_ids': []
                    })
                    etcd_snapshot_response = mock.Mock()
                    etcd_snapshot_response.etcd_index = 99
                    etcd_snapshot_response.leaves = [etcd_snapshot_node]
                    self.first_workload_read = False
                    return etcd_snapshot_response

            eventlet.sleep(10)
            return None

        etcd_client.read.side_effect = etcd_client_read

        with mock.patch.object(agent, 'call_driver') as call_driver:
            # Notify an endpoint.
            agent.etcd.on_endpoint_set(
                EtcdResponse(
                    value=json.dumps({
                        'state': 'active',
                        'name': 'tap1234',
                        'mac': 'fe:16:65:12:33:44',
                        'profile_ids': ['profile-1'],
                        'ipv4_nets': ['10.28.0.2/32'],
                        'ipv4_subnet_ids': ['v4subnet-1'],
                        'ipv4_gateway': '10.28.0.1',
                        'ipv6_nets': ['2001:db8:1::2/128'],
                        'ipv6_subnet_ids': ['v6subnet-1'],
                        'ipv6_gateway': '2001:db8:1::1'
                    })), 'hostname-ignored', 'openstack',
                'workload-id-ignored', 'endpoint-1')

            # Check expected subnets were read from etcd.
            etcd_client.read.assert_has_calls([
                mock.call(datamodel_v1.key_for_subnet('v4subnet-1'),
                          consistent=True),
                mock.call(datamodel_v1.key_for_subnet('v6subnet-1'),
                          consistent=True)
            ],
                                              any_order=True)
            etcd_client.read.reset_mock()

            # Check DHCP driver was asked to restart.
            call_driver.assert_called_with('restart', mock.ANY)

            # Notify another endpoint (using the same subnets).
            agent.etcd.on_endpoint_set(
                EtcdResponse(
                    value=json.dumps({
                        'state': 'active',
                        'name': 'tap5678',
                        'mac': 'fe:16:65:12:33:55',
                        'profile_ids': ['profile-1'],
                        'ipv4_nets': ['10.28.0.3/32'],
                        'ipv4_subnet_ids': ['v4subnet-1'],
                        'ipv4_gateway': '10.28.0.1',
                        'ipv6_nets': ['2001:db8:1::3/128'],
                        'ipv6_subnet_ids': ['v6subnet-1'],
                        'ipv6_gateway': '2001:db8:1::1',
                        'fqdn': 'calico-vm17.datcon.co.uk'
                    })), 'hostname-ignored', 'openstack',
                'workload-id-ignored', 'endpoint-2')

            # Check no further etcd reads.
            etcd_client.read.assert_not_called()

            # Check DHCP driver was asked to restart.
            call_driver.assert_called_with('restart', mock.ANY)

            # Notify deletion of the first endpoint.
            agent.etcd.on_endpoint_delete(None, 'hostname-ignored',
                                          'openstack', 'workload-id-ignored',
                                          'endpoint-1')

            # Check no further etcd reads.
            etcd_client.read.assert_not_called()

            # Check DHCP driver was asked to reload allocations.
            call_driver.assert_called_with('restart', mock.ANY)

            # Notify another endpoint using a new subnet.
            agent.etcd.on_endpoint_set(
                EtcdResponse(value=json.dumps({
                    'state': 'active',
                    'name': 'tapABCD',
                    'mac': 'fe:16:65:12:33:66',
                    'profile_ids': ['profile-1'],
                    'ipv4_nets': ['10.29.0.3/32'],
                    'ipv4_subnet_ids': ['v4subnet-2'],
                    'ipv4_gateway': '10.29.0.1',
                    'ipv6_nets': [],
                    'ipv6_subnet_ids': []
                })), 'hostname-ignored', 'openstack', 'workload-id-ignored',
                'endpoint-3')

            # Check expected new subnet was read from etcd.
            etcd_client.read.assert_has_calls([
                mock.call(datamodel_v1.key_for_subnet('v4subnet-2'),
                          consistent=True)
            ])
            etcd_client.read.reset_mock()

            # Check DHCP driver was asked to restart.
            call_driver.assert_called_with('restart', mock.ANY)

            # Set the endpoint watcher loop running.
            eventlet.spawn(agent.etcd.loop)

            # Report that the subnet watcher noticed a change.
            agent.etcd.on_subnet_set(None, 'some-subnet-X')
            eventlet.sleep(0.2)

            # Check DHCP driver was asked to restart.
            call_driver.assert_called_with('restart', mock.ANY)

            # Report that the subnet watcher loaded a new snapshot.
            agent.etcd.subnet_watcher._on_snapshot_loaded('ignored')
            eventlet.sleep(0.2)

            # Check DHCP driver was asked to restart.
            call_driver.assert_called_with('restart', mock.ANY)
    def test_mainline(self, etcd_client_cls):
        # Create the DHCP agent.
        agent = CalicoDhcpAgent()
        etcd_client = etcd_client_cls.return_value

        # Check that running it invokes the etcd watcher loop.
        with mock.patch.object(agent, 'etcd') as etcdobj:
            agent.run()
            etcdobj.loop.assert_called_with()

        # Notify initial snapshot (empty).
        with mock.patch.object(agent, 'call_driver') as call_driver:
            etcd_snapshot_response = mock.Mock()
            etcd_snapshot_response.leaves = []
            agent.etcd._on_snapshot_loaded(etcd_snapshot_response)
            call_driver.assert_not_called()

        # Prepare subnet reads for the endpoints that we will notify.
        self.first_workload_read = True

        def etcd_client_read(key, **kwargs):
            LOG.info('etcd_client_read %s %s', key, kwargs)
            if 'v4subnet-1' in key:
                self.assertEqual('/calico/dhcp/v1/subnet/v4subnet-1',
                                 key)
                return EtcdResponse(value=json.dumps({
                    'cidr': '10.28.0.0/24',
                    'gateway_ip': '10.28.0.1',
                    'host_routes': []
                }))
            if 'v6subnet-1' in key:
                return EtcdResponse(value=json.dumps({
                    'cidr': '2001:db8:1::/80',
                    'gateway_ip': '2001:db8:1::1'
                }))
            if 'v4subnet-2' in key:
                return EtcdResponse(value=json.dumps({
                    'cidr': '10.29.0.0/24',
                    'gateway_ip': '10.29.0.1',
                    'host_routes': [{'destination': '11.11.0.0/16',
                                     'nexthop': '10.65.0.1'}]
                }))
            if key == '/calico/v1/host/nj-ubuntu/workload':
                if self.first_workload_read:
                    # This is the recursive read that the CalicoEtcdWatcher
                    # loop makes after we've triggered it to resync.
                    etcd_snapshot_node = mock.Mock()
                    etcd_snapshot_node.action = 'exist'
                    etcd_snapshot_node.key = (
                        "/calico/v1/host/" +
                        socket.gethostname() +
                        "/workload/openstack" +
                        "/workload_id/endpoint/endpoint-4"
                    )
                    etcd_snapshot_node.value = json.dumps({
                        'state': 'active',
                        'name': 'tap1234',
                        'mac': 'fe:16:65:12:33:44',
                        'profile_ids': ['profile-1'],
                        'ipv4_nets': ['10.28.0.2/32'],
                        'ipv4_subnet_ids': ['v4subnet-1'],
                        'ipv4_gateway': '10.28.0.1',
                        'ipv6_nets': [],
                        'ipv6_subnet_ids': []
                    })
                    etcd_snapshot_response = mock.Mock()
                    etcd_snapshot_response.etcd_index = 99
                    etcd_snapshot_response.leaves = [etcd_snapshot_node]
                    self.first_workload_read = False
                    return etcd_snapshot_response

            eventlet.sleep(10)
            return None

        etcd_client.read.side_effect = etcd_client_read

        with mock.patch.object(agent, 'call_driver') as call_driver:
            # Notify an endpoint.
            agent.etcd.on_endpoint_set(EtcdResponse(value=json.dumps({
                'state': 'active',
                'name': 'tap1234',
                'mac': 'fe:16:65:12:33:44',
                'profile_ids': ['profile-1'],
                'ipv4_nets': ['10.28.0.2/32'],
                'ipv4_subnet_ids': ['v4subnet-1'],
                'ipv4_gateway': '10.28.0.1',
                'ipv6_nets': ['2001:db8:1::2/128'],
                'ipv6_subnet_ids': ['v6subnet-1'],
                'ipv6_gateway': '2001:db8:1::1'
            })),
                'hostname-ignored',
                'openstack',
                'workload-id-ignored',
                'endpoint-1'
            )

            # Check expected subnets were read from etcd.
            etcd_client.read.assert_has_calls([
                mock.call(datamodel_v1.key_for_subnet('v4subnet-1'),
                          consistent=True),
                mock.call(datamodel_v1.key_for_subnet('v6subnet-1'),
                          consistent=True)
            ],
                any_order=True)
            etcd_client.read.reset_mock()

            # Check DHCP driver was asked to restart.
            call_driver.assert_called_with('restart', mock.ANY)

            # Notify another endpoint (using the same subnets).
            agent.etcd.on_endpoint_set(EtcdResponse(value=json.dumps({
                'state': 'active',
                'name': 'tap5678',
                'mac': 'fe:16:65:12:33:55',
                'profile_ids': ['profile-1'],
                'ipv4_nets': ['10.28.0.3/32'],
                'ipv4_subnet_ids': ['v4subnet-1'],
                'ipv4_gateway': '10.28.0.1',
                'ipv6_nets': ['2001:db8:1::3/128'],
                'ipv6_subnet_ids': ['v6subnet-1'],
                'ipv6_gateway': '2001:db8:1::1',
                'fqdn': 'calico-vm17.datcon.co.uk'
            })),
                'hostname-ignored',
                'openstack',
                'workload-id-ignored',
                'endpoint-2'
            )

            # Check no further etcd reads.
            etcd_client.read.assert_not_called()

            # Check DHCP driver was asked to restart.
            call_driver.assert_called_with('restart', mock.ANY)

            # Notify deletion of the first endpoint.
            agent.etcd.on_endpoint_delete(None,
                                          'hostname-ignored',
                                          'openstack',
                                          'workload-id-ignored',
                                          'endpoint-1')

            # Check no further etcd reads.
            etcd_client.read.assert_not_called()

            # Check DHCP driver was asked to reload allocations.
            call_driver.assert_called_with('restart', mock.ANY)

            # Notify another endpoint using a new subnet.
            agent.etcd.on_endpoint_set(EtcdResponse(value=json.dumps({
                'state': 'active',
                'name': 'tapABCD',
                'mac': 'fe:16:65:12:33:66',
                'profile_ids': ['profile-1'],
                'ipv4_nets': ['10.29.0.3/32'],
                'ipv4_subnet_ids': ['v4subnet-2'],
                'ipv4_gateway': '10.29.0.1',
                'ipv6_nets': [],
                'ipv6_subnet_ids': []
            })),
                'hostname-ignored',
                'openstack',
                'workload-id-ignored',
                'endpoint-3'
            )

            # Check expected new subnet was read from etcd.
            etcd_client.read.assert_has_calls([
                mock.call(datamodel_v1.key_for_subnet('v4subnet-2'),
                          consistent=True)
            ])
            etcd_client.read.reset_mock()

            # Check DHCP driver was asked to restart.
            call_driver.assert_called_with('restart', mock.ANY)

            # Set the endpoint watcher loop running.
            eventlet.spawn(agent.etcd.loop)

            # Report that the subnet watcher noticed a change.
            agent.etcd.on_subnet_set(None, 'some-subnet-X')
            eventlet.sleep(0.2)

            # Check DHCP driver was asked to restart.
            call_driver.assert_called_with('restart', mock.ANY)

            # Report that the subnet watcher loaded a new snapshot.
            agent.etcd.subnet_watcher._on_snapshot_loaded('ignored')
            eventlet.sleep(0.2)

            # Check DHCP driver was asked to restart.
            call_driver.assert_called_with('restart', mock.ANY)
예제 #6
0
    def test_mainline(self):
        # Create the DHCP agent.
        agent = CalicoDhcpAgent()

        # Check that running it invokes the etcd watcher loop.
        with mock.patch.object(agent, 'etcd') as etcdobj:
            agent.run()
            etcdobj.start.assert_called_with()

        # Notify initial snapshot (empty).
        with mock.patch.object(agent, 'call_driver') as call_driver:
            snapshot_data = agent.etcd._pre_snapshot_hook()
            agent.etcd._post_snapshot_hook(snapshot_data)
            call_driver.assert_not_called()

        with mock.patch.object(agent, 'call_driver') as call_driver:
            # Notify subnets.
            agent.etcd.subnet_watcher.on_subnet_set(
                EtcdResponse(value=json.dumps({
                    'cidr': '10.28.0.0/24',
                    'gateway_ip': '10.28.0.1',
                    'host_routes': []
                })), 'v4subnet-1')
            agent.etcd.subnet_watcher.on_subnet_set(
                EtcdResponse(value=json.dumps({
                    'cidr': '2001:db8:1::/80',
                    'gateway_ip': '2001:db8:1::1'
                })), 'v6subnet-1')
            agent.etcd.subnet_watcher.on_subnet_set(
                EtcdResponse(value=json.dumps({
                    'cidr':
                    '10.29.0.0/24',
                    'gateway_ip':
                    '10.29.0.1',
                    'host_routes': [{
                        'destination': '11.11.0.0/16',
                        'nexthop': '10.65.0.1'
                    }]
                })), 'v4subnet-2')

            # Notify an endpoint.
            agent.etcd.on_endpoint_set(
                EtcdResponse(value=json.dumps({
                    'spec': {
                        'interfaceName': 'tap1234',
                        'mac': 'fe:16:65:12:33:44',
                        'profiles': ['profile-1'],
                        'ipNetworks': ['10.28.0.2/32', '2001:db8:1::2/128'],
                        'ipv4Gateway': '10.28.0.1',
                        'ipv6Gateway': '2001:db8:1::1'
                    }
                })), make_endpoint_name('endpoint-1'))

            # Check DHCP driver was asked to restart.
            call_driver.assert_called_with('restart', mock.ANY)

            # Notify another endpoint (using the same subnets).
            agent.etcd.on_endpoint_set(
                EtcdResponse(value=json.dumps({
                    'spec': {
                        'interfaceName': 'tap5678',
                        'mac': 'fe:16:65:12:33:55',
                        'profiles': ['profile-1'],
                        'ipNetworks': ['10.28.0.3/32', '2001:db8:1::3/128'],
                        'ipv4Gateway': '10.28.0.1',
                        'ipv6Gateway': '2001:db8:1::1',
                        'fqdn': 'calico-vm17.datcon.co.uk'
                    }
                })), make_endpoint_name('endpoint-2'))

            # Check DHCP driver was asked to restart.
            call_driver.assert_called_with('restart', mock.ANY)

            # Notify deletion of the first endpoint.
            agent.etcd.on_endpoint_delete(None,
                                          make_endpoint_name('endpoint-1'))

            # Check DHCP driver was asked to reload allocations.
            call_driver.assert_called_with('restart', mock.ANY)

            # Notify another endpoint using a new subnet.
            agent.etcd.on_endpoint_set(
                EtcdResponse(value=json.dumps({
                    'spec': {
                        'interfaceName': 'tapABCD',
                        'mac': 'fe:16:65:12:33:66',
                        'profiles': ['profile-1'],
                        'ipNetworks': ['10.29.0.3/32'],
                        'ipv4Gateway': '10.29.0.1',
                    }
                })), make_endpoint_name('endpoint-3'))

            # Check DHCP driver was asked to restart.
            call_driver.assert_called_with('restart', mock.ANY)