예제 #1
0
    def test_reload_allocations_stale_pid(self):
        (exp_host_name, exp_host_data,
         exp_addn_name, exp_addn_data,
         exp_opt_name, exp_opt_data,) = self._test_reload_allocation_data

        with mock.patch('__builtin__.open') as mock_open:
            mock_open.return_value.__enter__ = lambda s: s
            mock_open.return_value.__exit__ = mock.Mock()
            mock_open.return_value.readline.return_value = None

            with mock.patch('os.path.isdir') as isdir:
                isdir.return_value = True
                with mock.patch.object(dhcp.Dnsmasq, 'pid') as pid:
                    pid.__get__ = mock.Mock(return_value=5)
                    dm = dhcp.Dnsmasq(self.conf, FakeDualNetwork(),
                                      version=float(2.59))

                    method_name = '_make_subnet_interface_ip_map'
                    with mock.patch.object(dhcp.Dnsmasq, method_name) as ipmap:
                        ipmap.return_value = {}
                        dm.reload_allocations()
                        self.assertTrue(ipmap.called)

            self.safe.assert_has_calls([
                mock.call(exp_host_name, exp_host_data),
                mock.call(exp_addn_name, exp_addn_data),
                mock.call(exp_opt_name, exp_opt_data),
            ])
            mock_open.assert_called_once_with('/proc/5/cmdline', 'r')
예제 #2
0
    def test_output_opts_file_pxe_3port_2net(self):
        expected = """
tag:tag0,option:dns-server,8.8.8.8
tag:tag0,option:classless-static-route,20.0.0.1/24,20.0.0.1
tag:tag0,249,20.0.0.1/24,20.0.0.1
tag:tag0,option:router,192.168.0.1
tag:eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee,option:tftp-server,192.168.0.3
tag:eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee,option:server-ip-address,192.168.0.2
tag:eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee,option:bootfile-name,pxelinux.0
tag:ffffffff-ffff-ffff-ffff-ffffffffffff,option:tftp-server,192.168.1.3
tag:ffffffff-ffff-ffff-ffff-ffffffffffff,option:server-ip-address,192.168.1.2
tag:ffffffff-ffff-ffff-ffff-ffffffffffff,option:bootfile-name,pxelinux2.0
tag:44444444-4444-4444-4444-444444444444,option:tftp-server,192.168.1.3
tag:44444444-4444-4444-4444-444444444444,option:server-ip-address,192.168.1.2
tag:44444444-4444-4444-4444-444444444444,option:bootfile-name,pxelinux3.0"""
        expected = expected.lstrip()

        with mock.patch.object(dhcp.Dnsmasq, 'get_conf_file_name') as conf_fn:
            conf_fn.return_value = '/foo/opts'
            dm = dhcp.Dnsmasq(self.conf,
                              FakeDualV4Pxe3Ports(),
                              version=float(2.59))
            dm._output_opts_file()

        self.safe.assert_called_once_with('/foo/opts', expected)
예제 #3
0
    def test_reload_allocations(self):
        (exp_host_name, exp_host_data,
         exp_addn_name, exp_addn_data,
         exp_opt_name, exp_opt_data,) = self._test_reload_allocation_data

        exp_args = ['kill', '-HUP', 5]

        with mock.patch('os.path.isdir') as isdir:
            isdir.return_value = True
            with mock.patch.object(dhcp.Dnsmasq, 'active') as active:
                active.__get__ = mock.Mock(return_value=True)
                with mock.patch.object(dhcp.Dnsmasq, 'pid') as pid:
                    pid.__get__ = mock.Mock(return_value=5)
                    dm = dhcp.Dnsmasq(self.conf, FakeDualNetwork(),
                                      version=float(2.59))

                    method_name = '_make_subnet_interface_ip_map'
                    with mock.patch.object(dhcp.Dnsmasq,
                                           method_name) as ip_map:
                        ip_map.return_value = {}
                        dm.reload_allocations()
                        self.assertTrue(ip_map.called)

        self.safe.assert_has_calls([mock.call(exp_host_name, exp_host_data),
                                    mock.call(exp_addn_name, exp_addn_data),
                                    mock.call(exp_opt_name, exp_opt_data)])
        self.execute.assert_called_once_with(exp_args, 'sudo')
예제 #4
0
    def _test_spawn(self, extra_options, network=FakeDualNetwork(),
                    max_leases=16777216):
        def mock_get_conf_file_name(kind, ensure_conf_dir=False):
            return '/dhcp/%s/%s' % (network.id, kind)

        def fake_argv(index):
            if index == 0:
                return '/usr/local/bin/neutron-dhcp-agent'
            else:
                raise IndexError

        expected = [
            'ip',
            'netns',
            'exec',
            'qdhcp-ns',
            'env',
            'NEUTRON_NETWORK_ID=%s' % network.id,
            'dnsmasq',
            '--no-hosts',
            '--no-resolv',
            '--strict-order',
            '--bind-interfaces',
            '--interface=tap0',
            '--except-interface=lo',
            '--pid-file=/dhcp/%s/pid' % network.id,
            '--dhcp-hostsfile=/dhcp/%s/host' % network.id,
            '--dhcp-optsfile=/dhcp/%s/opts' % network.id,
            '--leasefile-ro']

        expected.extend(
            '--dhcp-range=set:tag%d,%s,static,86400s' %
            (i, s.cidr.split('/')[0])
            for i, s in enumerate(network.subnets)
        )
        expected.append('--dhcp-lease-max=%d' % max_leases)
        expected.extend(extra_options)

        self.execute.return_value = ('', '')

        attrs_to_mock = dict(
            [(a, mock.DEFAULT) for a in
                ['_output_opts_file', 'get_conf_file_name', 'interface_name']]
        )

        with mock.patch.multiple(dhcp.Dnsmasq, **attrs_to_mock) as mocks:
            mocks['get_conf_file_name'].side_effect = mock_get_conf_file_name
            mocks['_output_opts_file'].return_value = (
                '/dhcp/%s/opts' % network.id
            )
            mocks['interface_name'].__get__ = mock.Mock(return_value='tap0')

            with mock.patch.object(dhcp.sys, 'argv') as argv:
                argv.__getitem__.side_effect = fake_argv
                dm = dhcp.Dnsmasq(self.conf, network, version=float(2.59))
                dm.spawn_process()
                self.assertTrue(mocks['_output_opts_file'].called)
                self.execute.assert_called_once_with(expected,
                                                     root_helper='sudo',
                                                     check_exit_code=True)
예제 #5
0
    def test_reload_allocations(self):
        (exp_host_name, exp_host_data,
         exp_addn_name, exp_addn_data,
         exp_opt_name, exp_opt_data,) = self._test_reload_allocation_data

        exp_args = ['kill', '-HUP', 5]

        fake_net = FakeDualNetwork()
        dm = dhcp.Dnsmasq(self.conf, fake_net, version=float(2.59))

        with contextlib.nested(
            mock.patch('os.path.isdir', return_value=True),
            mock.patch.object(dhcp.Dnsmasq, 'active'),
            mock.patch.object(dhcp.Dnsmasq, 'pid'),
            mock.patch.object(dhcp.Dnsmasq, 'interface_name'),
            mock.patch.object(dhcp.Dnsmasq, '_make_subnet_interface_ip_map'),
            mock.patch.object(dm, 'device_manager')
        ) as (isdir, active, pid, interface_name, ip_map, device_manager):
            active.__get__ = mock.Mock(return_value=True)
            pid.__get__ = mock.Mock(return_value=5)
            interface_name.__get__ = mock.Mock(return_value='tap12345678-12')
            ip_map.return_value = {}
            dm.reload_allocations()

        self.assertTrue(ip_map.called)
        self.safe.assert_has_calls([mock.call(exp_host_name, exp_host_data),
                                    mock.call(exp_addn_name, exp_addn_data),
                                    mock.call(exp_opt_name, exp_opt_data)])
        self.execute.assert_called_once_with(exp_args, 'sudo')
        device_manager.update.assert_called_with(fake_net, 'tap12345678-12')
예제 #6
0
 def test_release_lease(self):
     dm = dhcp.Dnsmasq(self.conf, FakeDualNetwork(), version=float(2.59))
     dm.release_lease(mac_address=FakePort2.mac_address,
                      removed_ips=[FakePort2.fixed_ips[0].ip_address])
     exp_args = ['ip', 'netns', 'exec', 'qdhcp-ns', 'dhcp_release',
                 dm.interface_name, FakePort2.fixed_ips[0].ip_address,
                 FakePort2.mac_address]
     self.execute.assert_called_once_with(exp_args, root_helper='sudo',
                                          check_exit_code=True)
예제 #7
0
    def test_output_opts_file_multiple_agents_with_dns_provided(self):
        expected = """
tag:tag0,option:dns-server,8.8.8.8
tag:tag0,option:router,192.168.0.1""".lstrip()
        with mock.patch.object(dhcp.Dnsmasq, 'get_conf_file_name') as conf_fn:
            conf_fn.return_value = '/foo/opts'
            dm = dhcp.Dnsmasq(self.conf,
                              FakeV4MultipleAgentsWithDnsProvided(),
                              version=float(2.59))
            dm._output_opts_file()
        self.safe.assert_called_once_with('/foo/opts', expected)
예제 #8
0
    def test_make_subnet_interface_ip_map(self):
        with mock.patch('neutron.agent.linux.ip_lib.IPDevice') as ip_dev:
            ip_dev.return_value.addr.list.return_value = [{
                'cidr':
                '192.168.0.1/24'
            }]

            dm = dhcp.Dnsmasq(self.conf, FakeDualNetwork())

            self.assertEqual(dm._make_subnet_interface_ip_map(),
                             {FakeV4Subnet.id: '192.168.0.1'})
예제 #9
0
    def _test_spawn(self, extra_options):
        def mock_get_conf_file_name(kind, ensure_conf_dir=False):
            return '/dhcp/cccccccc-cccc-cccc-cccc-cccccccccccc/%s' % kind

        def fake_argv(index):
            if index == 0:
                return '/usr/local/bin/neutron-dhcp-agent'
            else:
                raise IndexError

        expected = [
            'ip', 'netns', 'exec', 'qdhcp-ns', 'env',
            'NEUTRON_RELAY_SOCKET_PATH=/dhcp/lease_relay',
            'NEUTRON_NETWORK_ID=cccccccc-cccc-cccc-cccc-cccccccccccc',
            'dnsmasq', '--no-hosts', '--no-resolv', '--strict-order',
            '--bind-interfaces', '--interface=tap0', '--except-interface=lo',
            '--pid-file=/dhcp/cccccccc-cccc-cccc-cccc-cccccccccccc/pid',
            '--dhcp-hostsfile=/dhcp/cccccccc-cccc-cccc-cccc-cccccccccccc/host',
            '--dhcp-optsfile=/dhcp/cccccccc-cccc-cccc-cccc-cccccccccccc/opts',
            ('--dhcp-script=/usr/local/bin/neutron-dhcp-agent-'
             'dnsmasq-lease-update'), '--leasefile-ro',
            '--dhcp-range=set:tag0,192.168.0.0,static,120s',
            '--dhcp-range=set:tag1,fdca:3ba5:a17a:4ba3::,static,120s'
        ]
        expected.extend(extra_options)

        self.execute.return_value = ('', '')
        delegate = mock.Mock()
        delegate.get_interface_name.return_value = 'tap0'

        attrs_to_mock = dict([
            (a, mock.DEFAULT) for a in
            ['_output_opts_file', 'get_conf_file_name', 'interface_name']
        ])

        with mock.patch.multiple(dhcp.Dnsmasq, **attrs_to_mock) as mocks:
            mocks['get_conf_file_name'].side_effect = mock_get_conf_file_name
            mocks['_output_opts_file'].return_value = (
                '/dhcp/cccccccc-cccc-cccc-cccc-cccccccccccc/opts')
            mocks['interface_name'].__get__ = mock.Mock(return_value='tap0')

            with mock.patch.object(dhcp.sys, 'argv') as argv:
                argv.__getitem__.side_effect = fake_argv
                dm = dhcp.Dnsmasq(self.conf,
                                  FakeDualNetwork(),
                                  device_delegate=delegate,
                                  namespace='qdhcp-ns',
                                  version=float(2.59))
                dm.spawn_process()
                self.assertTrue(mocks['_output_opts_file'].called)
                self.execute.assert_called_once_with(expected,
                                                     root_helper='sudo',
                                                     check_exit_code=True)
예제 #10
0
    def test_output_opts_file_single_dhcp_ver2_48(self):
        expected = """
tag0,option:dns-server,8.8.8.8
tag0,option:classless-static-route,20.0.0.1/24,20.0.0.1
tag0,249,20.0.0.1/24,20.0.0.1
tag0,option:router,192.168.0.1""".lstrip()
        with mock.patch.object(dhcp.Dnsmasq, 'get_conf_file_name') as conf_fn:
            conf_fn.return_value = '/foo/opts'
            dm = dhcp.Dnsmasq(self.conf, FakeDualNetworkSingleDHCP(),
                              version=float(2.48))
            dm._output_opts_file()

        self.safe.assert_called_once_with('/foo/opts', expected)
예제 #11
0
    def test_reload_allocations_stale_pid(self):
        exp_host_name = '/dhcp/cccccccc-cccc-cccc-cccc-cccccccccccc/host'
        exp_host_data = ('00:00:80:aa:bb:cc,host-192-168-0-2.openstacklocal,'
                         '192.168.0.2\n'
                         '00:00:f3:aa:bb:cc,host-fdca-3ba5-a17a-4ba3--2.'
                         'openstacklocal,fdca:3ba5:a17a:4ba3::2\n'
                         '00:00:0f:aa:bb:cc,host-192-168-0-3.openstacklocal,'
                         '192.168.0.3\n'
                         '00:00:0f:aa:bb:cc,host-fdca-3ba5-a17a-4ba3--3.'
                         'openstacklocal,fdca:3ba5:a17a:4ba3::3\n'
                         '00:00:0f:rr:rr:rr,host-192-168-0-1.openstacklocal,'
                         '192.168.0.1\n').lstrip()
        exp_host_data.replace('\n', '')
        exp_opt_name = '/dhcp/cccccccc-cccc-cccc-cccc-cccccccccccc/opts'
        exp_opt_data = "tag:tag0,option:router,192.168.0.1"
        fake_v6 = 'gdca:3ba5:a17a:4ba3::1'
        fake_v6_cidr = 'gdca:3ba5:a17a:4ba3::/64'
        exp_opt_data = """
tag:tag0,option:dns-server,8.8.8.8
tag:tag0,option:classless-static-route,20.0.0.1/24,20.0.0.1
tag:tag0,249,20.0.0.1/24,20.0.0.1
tag:tag0,option:router,192.168.0.1
tag:tag1,option:dns-server,%s
tag:tag1,option:classless-static-route,%s,%s
tag:tag1,249,%s,%s""".lstrip() % (fake_v6, fake_v6_cidr, fake_v6, fake_v6_cidr,
                                  fake_v6)

        with mock.patch('__builtin__.open') as mock_open:
            mock_open.return_value.__enter__ = lambda s: s
            mock_open.return_value.__exit__ = mock.Mock()
            mock_open.return_value.readline.return_value = None

            with mock.patch('os.path.isdir') as isdir:
                isdir.return_value = True
                with mock.patch.object(dhcp.Dnsmasq, 'pid') as pid:
                    pid.__get__ = mock.Mock(return_value=5)
                    dm = dhcp.Dnsmasq(self.conf,
                                      FakeDualNetwork(),
                                      version=float(2.59))

                    method_name = '_make_subnet_interface_ip_map'
                    with mock.patch.object(dhcp.Dnsmasq, method_name) as ipmap:
                        ipmap.return_value = {}
                        dm.reload_allocations()
                        self.assertTrue(ipmap.called)

            self.safe.assert_has_calls([
                mock.call(exp_host_name, exp_host_data),
                mock.call(exp_opt_name, exp_opt_data)
            ])
            mock_open.assert_called_once_with('/proc/5/cmdline', 'r')
예제 #12
0
    def test_reload_allocations(self):
        exp_host_name = '/dhcp/cccccccc-cccc-cccc-cccc-cccccccccccc/host'
        exp_host_data = ('00:00:80:aa:bb:cc,host-192-168-0-2.openstacklocal,'
                         '192.168.0.2\n'
                         '00:00:f3:aa:bb:cc,host-fdca-3ba5-a17a-4ba3--2.'
                         'openstacklocal,fdca:3ba5:a17a:4ba3::2\n'
                         '00:00:0f:aa:bb:cc,host-192-168-0-3.openstacklocal,'
                         '192.168.0.3\n'
                         '00:00:0f:aa:bb:cc,host-fdca-3ba5-a17a-4ba3--3.'
                         'openstacklocal,fdca:3ba5:a17a:4ba3::3\n'
                         '00:00:0f:rr:rr:rr,host-192-168-0-1.openstacklocal,'
                         '192.168.0.1\n').lstrip()
        exp_opt_name = '/dhcp/cccccccc-cccc-cccc-cccc-cccccccccccc/opts'
        exp_opt_data = "tag:tag0,option:router,192.168.0.1"
        fake_v6 = 'gdca:3ba5:a17a:4ba3::1'
        fake_v6_cidr = 'gdca:3ba5:a17a:4ba3::/64'
        exp_opt_data = """
tag:tag0,option:dns-server,8.8.8.8
tag:tag0,option:classless-static-route,20.0.0.1/24,20.0.0.1
tag:tag0,249,20.0.0.1/24,20.0.0.1
tag:tag0,option:router,192.168.0.1
tag:tag1,option:dns-server,%s
tag:tag1,option:classless-static-route,%s,%s
tag:tag1,249,%s,%s""".lstrip() % (fake_v6, fake_v6_cidr, fake_v6, fake_v6_cidr,
                                  fake_v6)

        exp_args = ['kill', '-HUP', 5]

        with mock.patch('os.path.isdir') as isdir:
            isdir.return_value = True
            with mock.patch.object(dhcp.Dnsmasq, 'active') as active:
                active.__get__ = mock.Mock(return_value=True)
                with mock.patch.object(dhcp.Dnsmasq, 'pid') as pid:
                    pid.__get__ = mock.Mock(return_value=5)
                    dm = dhcp.Dnsmasq(self.conf,
                                      FakeDualNetwork(),
                                      version=float(2.59))

                    method_name = '_make_subnet_interface_ip_map'
                    with mock.patch.object(dhcp.Dnsmasq,
                                           method_name) as ip_map:
                        ip_map.return_value = {}
                        dm.reload_allocations()
                        self.assertTrue(ip_map.called)

        self.safe.assert_has_calls([
            mock.call(exp_host_name, exp_host_data),
            mock.call(exp_opt_name, exp_opt_data)
        ])
        self.execute.assert_called_once_with(exp_args, 'sudo')
예제 #13
0
    def test_read_hosts_file_leases(self):
        filename = '/path/to/file'
        with mock.patch('os.path.exists') as mock_exists:
            mock_exists.return_value = True
            with mock.patch('__builtin__.open') as mock_open:
                mock_open.return_value.__enter__ = lambda s: s
                mock_open.return_value.__exit__ = mock.Mock()
                lines = ["00:00:80:aa:bb:cc,inst-name,192.168.0.1"]
                mock_open.return_value.readlines.return_value = lines

                dnsmasq = dhcp.Dnsmasq(self.conf, FakeDualNetwork())
                leases = dnsmasq._read_hosts_file_leases(filename)

        self.assertEqual(set([("192.168.0.1", "00:00:80:aa:bb:cc")]), leases)
        mock_exists.assert_called_once_with(filename)
        mock_open.assert_called_once_with(filename)
예제 #14
0
    def test_output_opts_file_no_neutron_router_on_subnet(self):
        expected = """
tag:tag0,option:classless-static-route,169.254.169.254/32,192.168.1.2
tag:tag0,249,169.254.169.254/32,192.168.1.2
tag:tag0,option:router,192.168.1.1""".lstrip()

        with mock.patch.object(dhcp.Dnsmasq, 'get_conf_file_name') as conf_fn:
            conf_fn.return_value = '/foo/opts'
            dm = dhcp.Dnsmasq(self.conf, FakeV4NetworkNoRouter(),
                              version=float(2.59))
            with mock.patch.object(dm, '_make_subnet_interface_ip_map') as ipm:
                ipm.return_value = {FakeV4SubnetNoRouter.id: '192.168.1.2'}

                dm._output_opts_file()
                self.assertTrue(ipm.called)

        self.safe.assert_called_once_with('/foo/opts', expected)
예제 #15
0
    def test_release_unused_leases_one_lease(self):
        dnsmasq = dhcp.Dnsmasq(self.conf, FakeDualNetwork())

        ip1 = '192.168.0.2'
        mac1 = '00:00:80:aa:bb:cc'
        ip2 = '192.168.0.3'
        mac2 = '00:00:80:cc:bb:aa'

        old_leases = set([(ip1, mac1), (ip2, mac2)])
        dnsmasq._read_hosts_file_leases = mock.Mock(return_value=old_leases)
        dnsmasq._output_hosts_file = mock.Mock()
        dnsmasq._release_lease = mock.Mock()
        dnsmasq.network.ports = [FakePort1()]

        dnsmasq._release_unused_leases()

        dnsmasq._release_lease.assert_has_calls([mock.call(mac2, ip2)],
                                                any_order=True)
예제 #16
0
    def test_output_opts_file_gateway_route(self):
        fake_v6 = 'gdca:3ba5:a17a:4ba3::1'
        fake_v6_cidr = 'gdca:3ba5:a17a:4ba3::/64'
        expected = """
tag:tag0,option:dns-server,8.8.8.8
tag:tag0,option:router,10.0.0.1
tag:tag1,option:dns-server,%s
tag:tag1,option:classless-static-route,%s,%s
tag:tag1,249,%s,%s""".lstrip() % (fake_v6, fake_v6_cidr, fake_v6, fake_v6_cidr,
                                  fake_v6)

        with mock.patch.object(dhcp.Dnsmasq, 'get_conf_file_name') as conf_fn:
            conf_fn.return_value = '/foo/opts'
            dm = dhcp.Dnsmasq(self.conf,
                              FakeDualNetworkGatewayRoute(),
                              version=float(2.59))
            dm._output_opts_file()

        self.safe.assert_called_once_with('/foo/opts', expected)