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)
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
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)
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)
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)
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)
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)
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, )
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
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
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})
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
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
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')
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
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
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)
def _is_distributed_dhcp_port(self, port): device_id = utils.get_dhcp_agent_device_id(port['network_id'], '') return device_id == port['device_id']