Ejemplo n.º 1
0
 def get_device_id(self, network):
     """Return a unique DHCP device ID for this host on the network."""
     # There could be more than one dhcp server per network, so create
     # a device id that combines host and network ids
     if self.conf.dhcp_distributed:
         return commonutils.get_dhcp_agent_device_id(network.id, '')
     else:
         return commonutils.get_dhcp_agent_device_id(network.id, self.conf.host)
Ejemplo n.º 2
0
 def convert_from_centralized_to_distributed(self, context, **kargs):
     """thread safe converting from centralized dhcp to distributed"""
     host = kargs.get('host_id')
     plugin = manager.NeutronManager.get_plugin()
     centralized_filter = {'binding:host_id': [host], 'device_owner': [constants.DEVICE_OWNER_DHCP]}
     centralized_ports = plugin.get_ports(context, centralized_filter)
     if not centralized_ports:
         return True
     LOG.info('convert_from_centralized_to_distributed, host:%s begin', host)
     finished_nets = set()
     for port in centralized_ports:
         net_id = port['network_id']
         if net_id in finished_nets:
             continue
         dhcp_port_filter = {'network_id': [net_id], 'device_owner': [constants.DEVICE_OWNER_DHCP]}
         dhcp_ports = plugin.get_ports(context, dhcp_port_filter, sorts = [('id', constants.SORT_DIRECTION_ASC)])
         if not dhcp_ports:
             continue
         min_port = dhcp_ports[0]
         if not self._is_distributed_dhcp_port(min_port):
             min_port['binding:host_id'] = ''
             min_port['device_id'] = utils.get_dhcp_agent_device_id(min_port['network_id'], '')
             if min_port['name'] is None or not min_port['name'].startswith('port@'):
                 min_port['name'] = 'distributed_dhcp_port'
             plugin.update_port(context, min_port['id'], {'port': min_port})
         rest_ports = dhcp_ports[1:]
         for p in rest_ports:
             try:
                 if p.get('binding:host_id') == host or not p.get('binding:host_id'):
                     plugin.delete_port(context, p['id'])
             except n_exc.PortNotFound as e:
                 LOG.warning('convert_from_centralized_to_distributed, port :%s already deleted', p['id'])
         finished_nets.add(net_id)
     LOG.info('convert_from_centralized_to_distributed, host:%s finish!', host)
     return True
Ejemplo n.º 3
0
    def test_update_reserved_dhcp_port(self):
        port = {'port': {'network_id': 'foo_network_id',
                         'device_owner': constants.DEVICE_OWNER_DHCP,
                         'fixed_ips': [{'subnet_id': 'foo_subnet_id'}]}
                }
        expected_port = {'port': {'network_id': 'foo_network_id',
                                  'device_owner': constants.DEVICE_OWNER_DHCP,
                                  portbindings.HOST_ID: 'foo_host',
                                  'fixed_ips': [{'subnet_id': 'foo_subnet_id'}]
                                  },
                         'id': 'foo_port_id'
                         }

        def _fake_port_action(plugin, context, port, action):
            self.assertEqual(expected_port, port)

        self.plugin.get_port.return_value = {
            'device_id': utils.get_dhcp_agent_device_id('foo_network_id',
                                                        'foo_host')}
        self.callbacks._port_action = _fake_port_action
        self.callbacks.update_dhcp_port(
            mock.Mock(), host='foo_host', port_id='foo_port_id', port=port)

        self.plugin.get_port.return_value = {
            'device_id': 'other_id'}
        self.assertRaises(exceptions.DhcpPortInUse,
                          self.callbacks.update_dhcp_port,
                          mock.Mock(),
                          host='foo_host',
                          port_id='foo_port_id',
                          port=port)
Ejemplo n.º 4
0
    def remove_network_from_dhcp_agent(self, context, id, network_id,
                                       notify=True):
        agent = self._get_agent(context, id)
        try:
            query = context.session.query(ndab_model.NetworkDhcpAgentBinding)
            binding = query.filter(
                ndab_model.NetworkDhcpAgentBinding.network_id == network_id,
                ndab_model.NetworkDhcpAgentBinding.dhcp_agent_id == id).one()
        except exc.NoResultFound:
            raise dhcpagentscheduler.NetworkNotHostedByDhcpAgent(
                network_id=network_id, agent_id=id)

        # reserve the port, so the ip is reused on a subsequent add
        device_id = utils.get_dhcp_agent_device_id(network_id,
                                                   agent['host'])
        filters = dict(device_id=[device_id])
        ports = self.get_ports(context, filters=filters)
        # NOTE(kevinbenton): there should only ever be one port per
        # DHCP agent per network so we don't have to worry about one
        # update_port passing and another failing
        for port in ports:
            port['device_id'] = n_const.DEVICE_ID_RESERVED_DHCP_PORT
            self.update_port(context, port['id'], dict(port=port))
        with context.session.begin():
            context.session.delete(binding)

        if not notify:
            return
        dhcp_notifier = self.agent_notifiers.get(constants.AGENT_TYPE_DHCP)
        if dhcp_notifier:
            dhcp_notifier.network_removed_from_agent(
                context, network_id, agent.host)
Ejemplo n.º 5
0
    def remove_network_from_dhcp_agent(self, context, id, network_id):
        agent = self._get_agent(context, id)
        with context.session.begin(subtransactions=True):
            try:
                query = context.session.query(NetworkDhcpAgentBinding)
                binding = query.filter(
                    NetworkDhcpAgentBinding.network_id == network_id,
                    NetworkDhcpAgentBinding.dhcp_agent_id == id).one()
            except exc.NoResultFound:
                raise dhcpagentscheduler.NetworkNotHostedByDhcpAgent(
                    network_id=network_id, agent_id=id)

            # reserve the port, so the ip is reused on a subsequent add
            device_id = utils.get_dhcp_agent_device_id(network_id,
                                                       agent['host'])
            filters = dict(device_id=[device_id])
            ports = self.get_ports(context, filters=filters)
            for port in ports:
                port['device_id'] = constants.DEVICE_ID_RESERVED_DHCP_PORT
                self.update_port(context, port['id'], dict(port=port))

            context.session.delete(binding)
        dhcp_notifier = self.agent_notifiers.get(constants.AGENT_TYPE_DHCP)
        if dhcp_notifier:
            dhcp_notifier.network_removed_from_agent(
                context, network_id, agent.host)
Ejemplo n.º 6
0
    def remove_network_from_dhcp_agent(self, context, id, network_id,
                                       notify=True):
        agent = self._get_agent(context, id)
        with context.session.begin(subtransactions=True):
            try:
                query = context.session.query(NetworkDhcpAgentBinding)
                query = query.filter(
                    NetworkDhcpAgentBinding.network_id == network_id,
                    NetworkDhcpAgentBinding.dhcp_agent_id == id)
                # just ensure the binding exists
                query.one()
            except exc.NoResultFound:
                raise dhcpagentscheduler.NetworkNotHostedByDhcpAgent(
                    network_id=network_id, agent_id=id)

            # reserve the port, so the ip is reused on a subsequent add
            device_id = utils.get_dhcp_agent_device_id(network_id,
                                                       agent['host'])
            filters = dict(device_id=[device_id])
            ports = self.get_ports(context, filters=filters)
            for port in ports:
                port['device_id'] = constants.DEVICE_ID_RESERVED_DHCP_PORT
                self.update_port(context, port['id'], dict(port=port))
            # avoid issues with query.one() object that was
            # loaded into the session
            query.delete(synchronize_session=False)

        if not notify:
            return
        dhcp_notifier = self.agent_notifiers.get(constants.AGENT_TYPE_DHCP)
        if dhcp_notifier:
            dhcp_notifier.network_removed_from_agent(
                context, network_id, agent.host)
Ejemplo n.º 7
0
    def remove_network_from_dhcp_agent(self, context, id, network_id,
                                       notify=True):
        agent = self._get_agent(context, id)
        binding_obj = network.NetworkDhcpAgentBinding.get_object(
            context, network_id=network_id, dhcp_agent_id=id)
        if not binding_obj:
            raise das_exc.NetworkNotHostedByDhcpAgent(
                network_id=network_id, agent_id=id)

        # reserve the port, so the ip is reused on a subsequent add
        device_id = utils.get_dhcp_agent_device_id(network_id,
                                                   agent['host'])
        filters = dict(device_id=[device_id])
        ports = self.get_ports(context, filters=filters)
        # NOTE(kevinbenton): there should only ever be one port per
        # DHCP agent per network so we don't have to worry about one
        # update_port passing and another failing
        for port in ports:
            port['device_id'] = constants.DEVICE_ID_RESERVED_DHCP_PORT
            try:
                self.update_port(context, port['id'], dict(port=port))
            except n_exc.PortNotFound:
                LOG.debug("DHCP port %s has been deleted concurrently",
                          port['id'])
        binding_obj.delete()

        if not notify:
            return
        dhcp_notifier = self.agent_notifiers.get(constants.AGENT_TYPE_DHCP)
        if dhcp_notifier:
            dhcp_notifier.network_removed_from_agent(
                context, network_id, agent.host)
Ejemplo n.º 8
0
    def test_update_reserved_dhcp_port(self):
        port = {
            "port": {
                "network_id": "foo_network_id",
                "device_owner": constants.DEVICE_OWNER_DHCP,
                "fixed_ips": [{"subnet_id": "foo_subnet_id"}],
            }
        }
        expected_port = {
            "port": {
                "network_id": "foo_network_id",
                "device_owner": constants.DEVICE_OWNER_DHCP,
                "binding:host_id": "foo_host",
                "fixed_ips": [{"subnet_id": "foo_subnet_id"}],
            },
            "id": "foo_port_id",
        }

        def _fake_port_action(plugin, context, port, action):
            self.assertEqual(expected_port, port)

        self.plugin.get_port.return_value = {"device_id": utils.get_dhcp_agent_device_id("foo_network_id", "foo_host")}
        self.callbacks._port_action = _fake_port_action
        self.callbacks.update_dhcp_port(mock.Mock(), host="foo_host", port_id="foo_port_id", port=port)

        self.plugin.get_port.return_value = {"device_id": "other_id"}
        self.assertRaises(
            n_exc.DhcpPortInUse,
            self.callbacks.update_dhcp_port,
            mock.Mock(),
            host="foo_host",
            port_id="foo_port_id",
            port=port,
        )
Ejemplo n.º 9
0
 def update_dhcp_port(self, context, **kwargs):
     """Update the dhcp port."""
     host = kwargs.get('host')
     port = kwargs.get('port')
     port['id'] = kwargs.get('port_id')
     port['port'][portbindings.HOST_ID] = host
     plugin = directory.get_plugin()
     try:
         network_id = port['port']['network_id']
         old_port = plugin.get_port(context, port['id'])
         if (old_port['device_id'] !=
                 constants.DEVICE_ID_RESERVED_DHCP_PORT and
             old_port['device_id'] !=
                 utils.get_dhcp_agent_device_id(network_id, host) or
             not self._is_dhcp_agent_hosting_network(plugin, context, host,
                 network_id)):
             raise exceptions.DhcpPortInUse(port_id=port['id'])
         LOG.debug('Update dhcp port %(port)s '
                   'from %(host)s.',
                   {'port': port,
                    'host': host})
         return self._port_action(plugin, context, port, 'update_port')
     except exceptions.PortNotFound:
         LOG.debug('Host %(host)s tried to update port '
                   '%(port_id)s which no longer exists.',
                   {'host': host, 'port_id': port['id']})
         return None
Ejemplo n.º 10
0
    def _create_port(self, fmt, net_id, expected_res_status=None,
                     arg_list=None, set_context=False, tenant_id=None,
                     **kwargs):
        tenant_id = tenant_id or self._tenant_id
        data = {'port': {'network_id': net_id,
                         'tenant_id': tenant_id}}

        for arg in (('admin_state_up', 'device_id',
                    'mac_address', 'name', 'fixed_ips',
                    'tenant_id', 'device_owner', 'security_groups',
                    'dns_name') + (arg_list or ())):
            # Arg must be present
            if arg in kwargs:
                data['port'][arg] = kwargs[arg]
        # create a dhcp port device id if one hasn't been supplied
        if ('device_owner' in kwargs and
            kwargs['device_owner'] == constants.DEVICE_OWNER_DHCP and
            'host' in kwargs and
            'device_id' not in kwargs):
            device_id = utils.get_dhcp_agent_device_id(net_id, kwargs['host'])
            data['port']['device_id'] = device_id
        port_req = self.new_create_request('ports', data, fmt)
        if set_context and tenant_id:
            # create a specific auth context for this request
            port_req.environ['neutron.context'] = context.Context(
                '', tenant_id)

        port_res = port_req.get_response(self.api)
        if expected_res_status:
            self.assertEqual(expected_res_status, port_res.status_int)
        return port_res
Ejemplo n.º 11
0
 def _check_and_update_dhcp_port(self, context, subnet):
     core_plugin = manager.NeutronManager.get_plugin()
     filters = {'network_id': [subnet['network_id']], 'device_owner': [const.DEVICE_OWNER_DHCP]}
     dhcp_ports = core_plugin.get_ports(context, filters)
     filters = {'network_id': [subnet['network_id']]}
     subnets_for_net = core_plugin.get_subnets(context, filters)
     if not dhcp_ports or len(dhcp_ports) < self.dhcp_agents_per_network:
         curr_dhcp_num = 0 if not dhcp_ports else len(dhcp_ports)
         for i in range(self.dhcp_agents_per_network - curr_dhcp_num):
             port_dict = dict(
                 admin_state_up=True,
                 device_id=commonutils.get_dhcp_agent_device_id(subnet['network_id'], ''),
                 network_id=subnet['network_id'],
                 tenant_id=subnet['tenant_id'],
                 mac_address=attributes.ATTR_NOT_SPECIFIED,
                 name='dhcp_port',
                 device_owner=const.DEVICE_OWNER_DHCP,
                 fixed_ips=[dict(subnet_id=s['id']) for s in subnets_for_net if s['enable_dhcp'] is True])
             dhcp_port_dict = {'port': port_dict}
             core_plugin.create_port(context, dhcp_port_dict)
     if dhcp_ports:
         dhcp_ports = dhcp_ports[:self.dhcp_agents_per_network]
         for dhcp_port in dhcp_ports:
             dhcp_subnets = [dict(subnet_id=s['id']) for s in subnets_for_net if s['enable_dhcp'] is True]
             if len(dhcp_subnets) == 0:
                 core_plugin.delete_port(context, dhcp_port['id'])
             else:
                 subnet_ids = set(fixed_ip['subnet_id'] for fixed_ip in dhcp_port['fixed_ips'])
                 if subnet['id'] not in subnet_ids and subnet['enable_dhcp']:
                     dhcp_port['fixed_ips'] += [dict(subnet_id=subnet['id'])]
                     core_plugin.update_port(context, dhcp_port['id'], {'port': dhcp_port})
Ejemplo n.º 12
0
 def network_dict_for_dhcp(self, dhcp_enabled=True, ip_version=4):
     net_id = uuidutils.generate_uuid()
     subnet_dict = self.create_subnet_dict(net_id, dhcp_enabled, ip_version)
     port_dict = self.create_port_dict(
         net_id, subnet_dict.id, mac_address=str(self._DHCP_PORT_MAC_ADDRESS), ip_version=ip_version
     )
     port_dict.device_id = common_utils.get_dhcp_agent_device_id(net_id, self.conf.host)
     net_dict = self.create_network_dict(net_id, [subnet_dict], [port_dict])
     return net_dict
Ejemplo n.º 13
0
 def _revert_dhcp_agent_device_id(self, context, nwa_info):
     device_owner = context._port['device_owner']
     device_id = context._port['device_id']
     if device_owner == constants.DEVICE_OWNER_DHCP and \
             device_id == neutron_const.DEVICE_ID_RESERVED_DHCP_PORT:
         # get device_id of dhcp agent even if it is reserved.
         nwa_info['device']['id'] = utils.get_dhcp_agent_device_id(
             context.network.current['id'],
             context._port.get('binding:host_id')
         )
     return nwa_info
Ejemplo n.º 14
0
 def update_dhcp_port(self, context, **kwargs):
     """Update the dhcp port."""
     host = kwargs.get('host')
     port = kwargs.get('port')
     port['id'] = kwargs.get('port_id')
     port['port'][portbindings.HOST_ID] = host
     plugin = manager.NeutronManager.get_plugin()
     old_port = plugin.get_port(context, port['id'])
     if (old_port['device_id'] != n_const.DEVICE_ID_RESERVED_DHCP_PORT
         and old_port['device_id'] !=
         utils.get_dhcp_agent_device_id(port['port']['network_id'], host)):
         raise n_exc.DhcpPortInUse(port_id=port['id'])
     LOG.debug('Update dhcp port %(port)s '
               'from %(host)s.',
               {'port': port,
                'host': host})
     return self._port_action(plugin, context, port, 'update_port')
Ejemplo n.º 15
0
 def _is_port_on_this_agent(self, port):
     thishost = utils.get_dhcp_agent_device_id(port['network_id'],
                                               self.conf.host)
     return port['device_id'] == thishost
Ejemplo n.º 16
0
 def _is_port_on_this_agent(self, port):
     thishost = utils.get_dhcp_agent_device_id(
         port['network_id'], self.conf.host)
     return port['device_id'] == thishost
Ejemplo n.º 17
0
 def get_device_id(self, network):
     """Return a unique DHCP device ID for this host on the network."""
     # There could be more than one dhcp server per network, so create
     # a device id that combines host and network ids
     return commonutils.get_dhcp_agent_device_id(network.id, self.conf.host)
Ejemplo n.º 18
0
 def _is_distributed_dhcp_port(self, port):
     device_id = utils.get_dhcp_agent_device_id(port['network_id'], '')
     return device_id == port['device_id']