Improve DHCP agent performance
Previously when starting the dhcp agent the sync_state() process would be extremely expensive as it would query quantum server for each network. In order to improve performance a get_active_networks_info() was added so this information could be retrieved in one query rather than doing a query for each active network. The second part of this patch optimizes the logic to avoid calling get_dhcp_port(). Previously, this method was called once for each network which makes a call to get_subnets() and get_ports() unnecessarily as the dhcp agent can determine itself if it needs to update a port or create a port for dhcp. This patch also threads the inital sync process and maintains backwards compatibility with the previous rpc api. There was also a trivial change to the nvp_plugin where filters are assumed to be a dict. implements blueprint improve-dhcp-agent-performance Change-Id: I3b631057f595250dad76516faa9b421789f60953
This commit is contained in:
parent
1566cfd697
commit
6189cbe4f5
@ -40,3 +40,7 @@ dhcp_driver = neutron.agent.linux.dhcp.Dnsmasq
|
|||||||
# they will be able to reach 169.254.169.254 through a router.
|
# they will be able to reach 169.254.169.254 through a router.
|
||||||
# This option requires enable_isolated_metadata = True
|
# This option requires enable_isolated_metadata = True
|
||||||
# enable_metadata_network = False
|
# enable_metadata_network = False
|
||||||
|
|
||||||
|
# Number of threads to use during sync process. Should not exceed connection
|
||||||
|
# pool size configured on server.
|
||||||
|
# num_sync_threads = 4
|
||||||
|
@ -67,6 +67,8 @@ class DhcpAgent(manager.Manager):
|
|||||||
help=_("Allows for serving metadata requests from a "
|
help=_("Allows for serving metadata requests from a "
|
||||||
"dedicated network. Requires "
|
"dedicated network. Requires "
|
||||||
"enable_isolated_metadata = True")),
|
"enable_isolated_metadata = True")),
|
||||||
|
cfg.IntOpt('num_sync_threads', default=4,
|
||||||
|
help=_('Number of threads to use during sync process.')),
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, host=None):
|
def __init__(self, host=None):
|
||||||
@ -147,15 +149,18 @@ class DhcpAgent(manager.Manager):
|
|||||||
def sync_state(self):
|
def sync_state(self):
|
||||||
"""Sync the local DHCP state with Neutron."""
|
"""Sync the local DHCP state with Neutron."""
|
||||||
LOG.info(_('Synchronizing state'))
|
LOG.info(_('Synchronizing state'))
|
||||||
known_networks = set(self.cache.get_network_ids())
|
pool = eventlet.GreenPool(cfg.CONF.num_sync_threads)
|
||||||
|
known_network_ids = set(self.cache.get_network_ids())
|
||||||
|
|
||||||
try:
|
try:
|
||||||
active_networks = set(self.plugin_rpc.get_active_networks())
|
active_networks = self.plugin_rpc.get_active_networks_info()
|
||||||
for deleted_id in known_networks - active_networks:
|
active_network_ids = set(network.id for network in active_networks)
|
||||||
|
for deleted_id in known_network_ids - active_network_ids:
|
||||||
self.disable_dhcp_helper(deleted_id)
|
self.disable_dhcp_helper(deleted_id)
|
||||||
|
|
||||||
for network_id in active_networks:
|
for network in active_networks:
|
||||||
self.refresh_dhcp_helper(network_id)
|
pool.spawn_n(self.configure_dhcp_for_network, network)
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
self.needs_resync = True
|
self.needs_resync = True
|
||||||
LOG.exception(_('Unable to sync network state.'))
|
LOG.exception(_('Unable to sync network state.'))
|
||||||
@ -180,7 +185,9 @@ class DhcpAgent(manager.Manager):
|
|||||||
self.needs_resync = True
|
self.needs_resync = True
|
||||||
LOG.exception(_('Network %s RPC info call failed.'), network_id)
|
LOG.exception(_('Network %s RPC info call failed.'), network_id)
|
||||||
return
|
return
|
||||||
|
self.configure_dhcp_for_network(network)
|
||||||
|
|
||||||
|
def configure_dhcp_for_network(self, network):
|
||||||
if not network.admin_state_up:
|
if not network.admin_state_up:
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -349,10 +356,12 @@ class DhcpPluginApi(proxy.RpcProxy):
|
|||||||
|
|
||||||
API version history:
|
API version history:
|
||||||
1.0 - Initial version.
|
1.0 - Initial version.
|
||||||
|
1.1 - Added get_active_networks_info, create_dhcp_port,
|
||||||
|
and update_dhcp_port methods.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
BASE_RPC_API_VERSION = '1.0'
|
BASE_RPC_API_VERSION = '1.1'
|
||||||
|
|
||||||
def __init__(self, topic, context):
|
def __init__(self, topic, context):
|
||||||
super(DhcpPluginApi, self).__init__(
|
super(DhcpPluginApi, self).__init__(
|
||||||
@ -360,11 +369,13 @@ class DhcpPluginApi(proxy.RpcProxy):
|
|||||||
self.context = context
|
self.context = context
|
||||||
self.host = cfg.CONF.host
|
self.host = cfg.CONF.host
|
||||||
|
|
||||||
def get_active_networks(self):
|
def get_active_networks_info(self):
|
||||||
"""Make a remote process call to retrieve the active networks."""
|
"""Make a remote process call to retrieve all network info."""
|
||||||
return self.call(self.context,
|
networks = self.call(self.context,
|
||||||
self.make_msg('get_active_networks', host=self.host),
|
self.make_msg('get_active_networks_info',
|
||||||
topic=self.topic)
|
host=self.host),
|
||||||
|
topic=self.topic)
|
||||||
|
return [DictModel(n) for n in networks]
|
||||||
|
|
||||||
def get_network_info(self, network_id):
|
def get_network_info(self, network_id):
|
||||||
"""Make a remote process call to retrieve network info."""
|
"""Make a remote process call to retrieve network info."""
|
||||||
@ -378,8 +389,25 @@ class DhcpPluginApi(proxy.RpcProxy):
|
|||||||
"""Make a remote process call to create the dhcp port."""
|
"""Make a remote process call to create the dhcp port."""
|
||||||
return DictModel(self.call(self.context,
|
return DictModel(self.call(self.context,
|
||||||
self.make_msg('get_dhcp_port',
|
self.make_msg('get_dhcp_port',
|
||||||
network_id=network_id,
|
network_id=network_id,
|
||||||
device_id=device_id,
|
device_id=device_id,
|
||||||
|
host=self.host),
|
||||||
|
topic=self.topic))
|
||||||
|
|
||||||
|
def create_dhcp_port(self, port):
|
||||||
|
"""Make a remote process call to create the dhcp port."""
|
||||||
|
return DictModel(self.call(self.context,
|
||||||
|
self.make_msg('create_dhcp_port',
|
||||||
|
port=port,
|
||||||
|
host=self.host),
|
||||||
|
topic=self.topic))
|
||||||
|
|
||||||
|
def update_dhcp_port(self, port_id, port):
|
||||||
|
"""Make a remote process call to update the dhcp port."""
|
||||||
|
return DictModel(self.call(self.context,
|
||||||
|
self.make_msg('update_dhcp_port',
|
||||||
|
port_id=port_id,
|
||||||
|
port=port,
|
||||||
host=self.host),
|
host=self.host),
|
||||||
topic=self.topic))
|
topic=self.topic))
|
||||||
|
|
||||||
@ -515,11 +543,8 @@ class DeviceManager(object):
|
|||||||
"'%s'") % conf.interface_driver
|
"'%s'") % conf.interface_driver
|
||||||
raise SystemExit(msg)
|
raise SystemExit(msg)
|
||||||
|
|
||||||
def get_interface_name(self, network, port=None):
|
def get_interface_name(self, network, port):
|
||||||
"""Return interface(device) name for use by the DHCP process."""
|
"""Return interface(device) name for use by the DHCP process."""
|
||||||
if not port:
|
|
||||||
device_id = self.get_device_id(network)
|
|
||||||
port = self.plugin.get_dhcp_port(network.id, device_id)
|
|
||||||
return self.driver.get_device_name(port)
|
return self.driver.get_device_name(port)
|
||||||
|
|
||||||
def get_device_id(self, network):
|
def get_device_id(self, network):
|
||||||
@ -577,11 +602,69 @@ class DeviceManager(object):
|
|||||||
|
|
||||||
device.route.delete_gateway(gateway)
|
device.route.delete_gateway(gateway)
|
||||||
|
|
||||||
|
def setup_dhcp_port(self, network):
|
||||||
|
"""Create/update DHCP port for the host if needed and return port."""
|
||||||
|
|
||||||
|
device_id = self.get_device_id(network)
|
||||||
|
subnets = {}
|
||||||
|
dhcp_enabled_subnet_ids = []
|
||||||
|
for subnet in network.subnets:
|
||||||
|
if subnet.enable_dhcp:
|
||||||
|
dhcp_enabled_subnet_ids.append(subnet.id)
|
||||||
|
subnets[subnet.id] = subnet
|
||||||
|
|
||||||
|
dhcp_port = None
|
||||||
|
for port in network.ports:
|
||||||
|
port_device_id = getattr(port, 'device_id', None)
|
||||||
|
if port_device_id == device_id:
|
||||||
|
port_fixed_ips = []
|
||||||
|
for fixed_ip in port.fixed_ips:
|
||||||
|
port_fixed_ips.append({'subnet_id': fixed_ip.subnet_id,
|
||||||
|
'ip_address': fixed_ip.ip_address})
|
||||||
|
if fixed_ip.subnet_id in dhcp_enabled_subnet_ids:
|
||||||
|
dhcp_enabled_subnet_ids.remove(fixed_ip.subnet_id)
|
||||||
|
|
||||||
|
# If there are dhcp_enabled_subnet_ids here that means that
|
||||||
|
# we need to add those to the port and call update.
|
||||||
|
if dhcp_enabled_subnet_ids:
|
||||||
|
port_fixed_ips.extend(
|
||||||
|
[dict(subnet_id=s) for s in dhcp_enabled_subnet_ids])
|
||||||
|
dhcp_port = self.plugin.update_dhcp_port(
|
||||||
|
port.id, {'port': {'fixed_ips': port_fixed_ips}})
|
||||||
|
else:
|
||||||
|
dhcp_port = port
|
||||||
|
# break since we found port that matches device_id
|
||||||
|
break
|
||||||
|
|
||||||
|
# DHCP port has not yet been created.
|
||||||
|
if dhcp_port is None:
|
||||||
|
LOG.debug(_('DHCP port %(device_id)s on network %(network_id)s'
|
||||||
|
' does not yet exist.'), {'device_id': device_id,
|
||||||
|
'network_id': network.id})
|
||||||
|
port_dict = dict(
|
||||||
|
name='',
|
||||||
|
admin_state_up=True,
|
||||||
|
device_id=device_id,
|
||||||
|
network_id=network.id,
|
||||||
|
tenant_id=network.tenant_id,
|
||||||
|
fixed_ips=[dict(subnet_id=s) for s in dhcp_enabled_subnet_ids])
|
||||||
|
dhcp_port = self.plugin.create_dhcp_port({'port': port_dict})
|
||||||
|
|
||||||
|
# Convert subnet_id to subnet dict
|
||||||
|
fixed_ips = [dict(subnet_id=fixed_ip.subnet_id,
|
||||||
|
ip_address=fixed_ip.ip_address,
|
||||||
|
subnet=subnets[fixed_ip.subnet_id])
|
||||||
|
for fixed_ip in dhcp_port.fixed_ips]
|
||||||
|
|
||||||
|
ips = [DictModel(item) if isinstance(item, dict) else item
|
||||||
|
for item in fixed_ips]
|
||||||
|
dhcp_port.fixed_ips = ips
|
||||||
|
|
||||||
|
return dhcp_port
|
||||||
|
|
||||||
def setup(self, network, reuse_existing=False):
|
def setup(self, network, reuse_existing=False):
|
||||||
"""Create and initialize a device for network's DHCP on this host."""
|
"""Create and initialize a device for network's DHCP on this host."""
|
||||||
device_id = self.get_device_id(network)
|
port = self.setup_dhcp_port(network)
|
||||||
port = self.plugin.get_dhcp_port(network.id, device_id)
|
|
||||||
|
|
||||||
interface_name = self.get_interface_name(network, port)
|
interface_name = self.get_interface_name(network, port)
|
||||||
|
|
||||||
if self.conf.use_namespaces:
|
if self.conf.use_namespaces:
|
||||||
|
@ -71,7 +71,7 @@ class PluginApi(proxy.RpcProxy):
|
|||||||
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
BASE_RPC_API_VERSION = '1.0'
|
BASE_RPC_API_VERSION = '1.1'
|
||||||
|
|
||||||
def __init__(self, topic):
|
def __init__(self, topic):
|
||||||
super(PluginApi, self).__init__(
|
super(PluginApi, self).__init__(
|
||||||
|
@ -29,10 +29,9 @@ LOG = logging.getLogger(__name__)
|
|||||||
class DhcpRpcCallbackMixin(object):
|
class DhcpRpcCallbackMixin(object):
|
||||||
"""A mix-in that enable DHCP agent support in plugin implementations."""
|
"""A mix-in that enable DHCP agent support in plugin implementations."""
|
||||||
|
|
||||||
def get_active_networks(self, context, **kwargs):
|
def _get_active_networks(self, context, **kwargs):
|
||||||
"""Retrieve and return a list of the active network ids."""
|
"""Retrieve and return a list of the active networks."""
|
||||||
host = kwargs.get('host')
|
host = kwargs.get('host')
|
||||||
LOG.debug(_('Network list requested from %s'), host)
|
|
||||||
plugin = manager.NeutronManager.get_plugin()
|
plugin = manager.NeutronManager.get_plugin()
|
||||||
if utils.is_extension_supported(
|
if utils.is_extension_supported(
|
||||||
plugin, constants.DHCP_AGENT_SCHEDULER_EXT_ALIAS):
|
plugin, constants.DHCP_AGENT_SCHEDULER_EXT_ALIAS):
|
||||||
@ -43,8 +42,37 @@ class DhcpRpcCallbackMixin(object):
|
|||||||
else:
|
else:
|
||||||
filters = dict(admin_state_up=[True])
|
filters = dict(admin_state_up=[True])
|
||||||
nets = plugin.get_networks(context, filters=filters)
|
nets = plugin.get_networks(context, filters=filters)
|
||||||
|
return nets
|
||||||
|
|
||||||
|
def get_active_networks(self, context, **kwargs):
|
||||||
|
"""Retrieve and return a list of the active network ids."""
|
||||||
|
# NOTE(arosen): This method is no longer used by the DHCP agent but is
|
||||||
|
# left so that quantum-dhcp-agents will still continue to work if
|
||||||
|
# quantum-server is upgraded and not the agent.
|
||||||
|
host = kwargs.get('host')
|
||||||
|
LOG.debug(_('get_active_networks requested from %s'), host)
|
||||||
|
nets = self._get_active_networks(context, **kwargs)
|
||||||
return [net['id'] for net in nets]
|
return [net['id'] for net in nets]
|
||||||
|
|
||||||
|
def get_active_networks_info(self, context, **kwargs):
|
||||||
|
"""Returns all the networks/subnets/ports in system."""
|
||||||
|
host = kwargs.get('host')
|
||||||
|
LOG.debug(_('get_active_networks_info from %s'), host)
|
||||||
|
networks = self._get_active_networks(context, **kwargs)
|
||||||
|
plugin = manager.NeutronManager.get_plugin()
|
||||||
|
filters = {'network_id': [network['id'] for network in networks]}
|
||||||
|
ports = plugin.get_ports(context, filters=filters)
|
||||||
|
filters['enable_dhcp'] = [True]
|
||||||
|
subnets = plugin.get_subnets(context, filters=filters)
|
||||||
|
|
||||||
|
for network in networks:
|
||||||
|
network['subnets'] = [subnet for subnet in subnets
|
||||||
|
if subnet['network_id'] == network['id']]
|
||||||
|
network['ports'] = [port for port in ports
|
||||||
|
if port['network_id'] == network['id']]
|
||||||
|
|
||||||
|
return networks
|
||||||
|
|
||||||
def get_network_info(self, context, **kwargs):
|
def get_network_info(self, context, **kwargs):
|
||||||
"""Retrieve and return a extended information about a network."""
|
"""Retrieve and return a extended information about a network."""
|
||||||
network_id = kwargs.get('network_id')
|
network_id = kwargs.get('network_id')
|
||||||
@ -68,6 +96,10 @@ class DhcpRpcCallbackMixin(object):
|
|||||||
network state.
|
network state.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
# NOTE(arosen): This method is no longer used by the DHCP agent but is
|
||||||
|
# left so that quantum-dhcp-agents will still continue to work if
|
||||||
|
# quantum-server is upgraded and not the agent.
|
||||||
|
|
||||||
host = kwargs.get('host')
|
host = kwargs.get('host')
|
||||||
network_id = kwargs.get('network_id')
|
network_id = kwargs.get('network_id')
|
||||||
device_id = kwargs.get('device_id')
|
device_id = kwargs.get('device_id')
|
||||||
@ -191,3 +223,30 @@ class DhcpRpcCallbackMixin(object):
|
|||||||
|
|
||||||
plugin.update_fixed_ip_lease_expiration(context, network_id,
|
plugin.update_fixed_ip_lease_expiration(context, network_id,
|
||||||
ip_address, lease_remaining)
|
ip_address, lease_remaining)
|
||||||
|
|
||||||
|
def create_dhcp_port(self, context, **kwargs):
|
||||||
|
"""Create the dhcp port."""
|
||||||
|
host = kwargs.get('host')
|
||||||
|
port = kwargs.get('port')
|
||||||
|
LOG.debug(_('Create dhcp port %(port)s '
|
||||||
|
'from %(host)s.'),
|
||||||
|
{'port': port,
|
||||||
|
'host': host})
|
||||||
|
|
||||||
|
port['port']['device_owner'] = constants.DEVICE_OWNER_DHCP
|
||||||
|
if 'mac_address' not in port['port']:
|
||||||
|
port['port']['mac_address'] = attributes.ATTR_NOT_SPECIFIED
|
||||||
|
plugin = manager.NeutronManager.get_plugin()
|
||||||
|
return plugin.create_port(context, port)
|
||||||
|
|
||||||
|
def update_dhcp_port(self, context, **kwargs):
|
||||||
|
"""Update the dhcp port."""
|
||||||
|
host = kwargs.get('host')
|
||||||
|
port_id = kwargs.get('port_id')
|
||||||
|
port = kwargs.get('port')
|
||||||
|
LOG.debug(_('Update dhcp port %(port)s '
|
||||||
|
'from %(host)s.'),
|
||||||
|
{'port': port,
|
||||||
|
'host': host})
|
||||||
|
plugin = manager.NeutronManager.get_plugin()
|
||||||
|
return plugin.update_port(context, port_id, port)
|
||||||
|
@ -323,7 +323,7 @@ class ServerPool(object):
|
|||||||
|
|
||||||
class RpcProxy(dhcp_rpc_base.DhcpRpcCallbackMixin):
|
class RpcProxy(dhcp_rpc_base.DhcpRpcCallbackMixin):
|
||||||
|
|
||||||
RPC_API_VERSION = '1.0'
|
RPC_API_VERSION = '1.1'
|
||||||
|
|
||||||
def create_rpc_dispatcher(self):
|
def create_rpc_dispatcher(self):
|
||||||
return q_rpc.PluginRpcDispatcher([self])
|
return q_rpc.PluginRpcDispatcher([self])
|
||||||
|
@ -163,10 +163,12 @@ class AgentNotifierApi(proxy.RpcProxy,
|
|||||||
|
|
||||||
API version history:
|
API version history:
|
||||||
1.0 - Initial version.
|
1.0 - Initial version.
|
||||||
|
1.1 - Added get_active_networks_info, create_dhcp_port,
|
||||||
|
and update_dhcp_port methods.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
BASE_RPC_API_VERSION = '1.0'
|
BASE_RPC_API_VERSION = '1.1'
|
||||||
|
|
||||||
def __init__(self, topic):
|
def __init__(self, topic):
|
||||||
super(AgentNotifierApi, self).__init__(
|
super(AgentNotifierApi, self).__init__(
|
||||||
|
@ -32,7 +32,7 @@ class HyperVRpcCallbacks(
|
|||||||
l3_rpc_base.L3RpcCallbackMixin):
|
l3_rpc_base.L3RpcCallbackMixin):
|
||||||
|
|
||||||
# Set RPC API version to 1.0 by default.
|
# Set RPC API version to 1.0 by default.
|
||||||
RPC_API_VERSION = '1.0'
|
RPC_API_VERSION = '1.1'
|
||||||
|
|
||||||
def __init__(self, notifier):
|
def __init__(self, notifier):
|
||||||
self.notifier = notifier
|
self.notifier = notifier
|
||||||
|
@ -149,10 +149,13 @@ class AgentNotifierApi(proxy.RpcProxy,
|
|||||||
|
|
||||||
API version history:
|
API version history:
|
||||||
1.0 - Initial version.
|
1.0 - Initial version.
|
||||||
|
1.1 - Added get_active_networks_info, create_dhcp_port,
|
||||||
|
and update_dhcp_port methods.
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
BASE_RPC_API_VERSION = '1.0'
|
BASE_RPC_API_VERSION = '1.1'
|
||||||
|
|
||||||
def __init__(self, topic):
|
def __init__(self, topic):
|
||||||
super(AgentNotifierApi, self).__init__(
|
super(AgentNotifierApi, self).__init__(
|
||||||
|
@ -166,9 +166,12 @@ class AgentNotifierApi(proxy.RpcProxy,
|
|||||||
|
|
||||||
API version history:
|
API version history:
|
||||||
1.0 - Initial version.
|
1.0 - Initial version.
|
||||||
|
1.1 - Added get_active_networks_info, create_dhcp_port,
|
||||||
|
update_dhcp_port, and removed get_dhcp_port methods.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
BASE_RPC_API_VERSION = '1.0'
|
BASE_RPC_API_VERSION = '1.1'
|
||||||
|
|
||||||
def __init__(self, topic):
|
def __init__(self, topic):
|
||||||
super(AgentNotifierApi, self).__init__(
|
super(AgentNotifierApi, self).__init__(
|
||||||
|
@ -602,7 +602,7 @@ class NECPluginV2AgentNotifierApi(proxy.RpcProxy,
|
|||||||
|
|
||||||
class DhcpRpcCallback(dhcp_rpc_base.DhcpRpcCallbackMixin):
|
class DhcpRpcCallback(dhcp_rpc_base.DhcpRpcCallbackMixin):
|
||||||
# DhcpPluginApi BASE_RPC_API_VERSION
|
# DhcpPluginApi BASE_RPC_API_VERSION
|
||||||
RPC_API_VERSION = '1.0'
|
RPC_API_VERSION = '1.1'
|
||||||
|
|
||||||
|
|
||||||
class L3RpcCallback(l3_rpc_base.L3RpcCallbackMixin):
|
class L3RpcCallback(l3_rpc_base.L3RpcCallbackMixin):
|
||||||
|
@ -111,7 +111,7 @@ def create_nvp_cluster(cluster_opts, concurrent_connections,
|
|||||||
class NVPRpcCallbacks(dhcp_rpc_base.DhcpRpcCallbackMixin):
|
class NVPRpcCallbacks(dhcp_rpc_base.DhcpRpcCallbackMixin):
|
||||||
|
|
||||||
# Set RPC API version to 1.0 by default.
|
# Set RPC API version to 1.0 by default.
|
||||||
RPC_API_VERSION = '1.0'
|
RPC_API_VERSION = '1.1'
|
||||||
|
|
||||||
def create_rpc_dispatcher(self):
|
def create_rpc_dispatcher(self):
|
||||||
'''Get the rpc dispatcher for this manager.
|
'''Get the rpc dispatcher for this manager.
|
||||||
@ -1033,6 +1033,8 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
return net
|
return net
|
||||||
|
|
||||||
def get_ports(self, context, filters=None, fields=None):
|
def get_ports(self, context, filters=None, fields=None):
|
||||||
|
if filters is None:
|
||||||
|
filters = {}
|
||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
neutron_lports = super(NvpPluginV2, self).get_ports(
|
neutron_lports = super(NvpPluginV2, self).get_ports(
|
||||||
context, filters)
|
context, filters)
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import copy
|
||||||
import os
|
import os
|
||||||
import socket
|
import socket
|
||||||
import sys
|
import sys
|
||||||
@ -53,14 +54,24 @@ class FakeModel:
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.__dict__)
|
return str(self.__dict__)
|
||||||
|
|
||||||
|
fake_tenant_id = 'aaaaaaaa-aaaa-aaaa-aaaaaaaaaaaa'
|
||||||
|
fake_subnet1_allocation_pools = FakeModel('', start='172.9.9.2',
|
||||||
|
end='172.9.9.254')
|
||||||
fake_subnet1 = FakeModel('bbbbbbbb-bbbb-bbbb-bbbbbbbbbbbb',
|
fake_subnet1 = FakeModel('bbbbbbbb-bbbb-bbbb-bbbbbbbbbbbb',
|
||||||
network_id='12345678-1234-5678-1234567890ab',
|
network_id='12345678-1234-5678-1234567890ab',
|
||||||
cidr='172.9.9.0/24', enable_dhcp=True)
|
cidr='172.9.9.0/24', enable_dhcp=True, name='',
|
||||||
|
tenant_id=fake_tenant_id, gateway_ip='172.9.9.1',
|
||||||
|
host_routes=[], dns_nameservers=[], ip_version=4,
|
||||||
|
allocation_pools=fake_subnet1_allocation_pools)
|
||||||
|
|
||||||
|
fake_subnet2_allocation_pools = FakeModel('', start='172.9.8.2',
|
||||||
|
end='172.9.8.254')
|
||||||
fake_subnet2 = FakeModel('dddddddd-dddd-dddd-dddddddddddd',
|
fake_subnet2 = FakeModel('dddddddd-dddd-dddd-dddddddddddd',
|
||||||
network_id='12345678-1234-5678-1234567890ab',
|
network_id='12345678-1234-5678-1234567890ab',
|
||||||
cidr='172.9.9.0/24', enable_dhcp=False)
|
cidr='172.9.8.0/24', enable_dhcp=False, name='',
|
||||||
|
tenant_id=fake_tenant_id, gateway_ip='172.9.8.1',
|
||||||
|
host_routes=[], dns_nameservers=[], ip_version=4,
|
||||||
|
allocation_pools=fake_subnet2_allocation_pools)
|
||||||
|
|
||||||
fake_subnet3 = FakeModel('bbbbbbbb-1111-2222-bbbbbbbbbbbb',
|
fake_subnet3 = FakeModel('bbbbbbbb-1111-2222-bbbbbbbbbbbb',
|
||||||
network_id='12345678-1234-5678-1234567890ab',
|
network_id='12345678-1234-5678-1234567890ab',
|
||||||
@ -71,14 +82,20 @@ fake_meta_subnet = FakeModel('bbbbbbbb-1111-2222-bbbbbbbbbbbb',
|
|||||||
cidr='169.254.169.252/30',
|
cidr='169.254.169.252/30',
|
||||||
gateway_ip='169.254.169.253', enable_dhcp=True)
|
gateway_ip='169.254.169.253', enable_dhcp=True)
|
||||||
|
|
||||||
fake_fixed_ip = FakeModel('', subnet=fake_subnet1, ip_address='172.9.9.9')
|
fake_fixed_ip1 = FakeModel('', subnet_id=fake_subnet1.id,
|
||||||
|
ip_address='172.9.9.9')
|
||||||
fake_meta_fixed_ip = FakeModel('', subnet=fake_meta_subnet,
|
fake_meta_fixed_ip = FakeModel('', subnet=fake_meta_subnet,
|
||||||
ip_address='169.254.169.254')
|
ip_address='169.254.169.254')
|
||||||
|
fake_allocation_pool_subnet1 = FakeModel('', start='172.9.9.2',
|
||||||
|
end='172.9.9.254')
|
||||||
|
|
||||||
|
|
||||||
fake_port1 = FakeModel('12345678-1234-aaaa-1234567890ab',
|
fake_port1 = FakeModel('12345678-1234-aaaa-1234567890ab',
|
||||||
|
device_id='dhcp-12345678-1234-aaaa-1234567890ab',
|
||||||
|
allocation_pools=fake_subnet1_allocation_pools,
|
||||||
mac_address='aa:bb:cc:dd:ee:ff',
|
mac_address='aa:bb:cc:dd:ee:ff',
|
||||||
network_id='12345678-1234-5678-1234567890ab',
|
network_id='12345678-1234-5678-1234567890ab',
|
||||||
fixed_ips=[fake_fixed_ip])
|
fixed_ips=[fake_fixed_ip1])
|
||||||
|
|
||||||
fake_port2 = FakeModel('12345678-1234-aaaa-123456789000',
|
fake_port2 = FakeModel('12345678-1234-aaaa-123456789000',
|
||||||
mac_address='aa:bb:cc:dd:ee:99',
|
mac_address='aa:bb:cc:dd:ee:99',
|
||||||
@ -263,7 +280,7 @@ class TestDhcpAgent(base.BaseTestCase):
|
|||||||
def _test_sync_state_helper(self, known_networks, active_networks):
|
def _test_sync_state_helper(self, known_networks, active_networks):
|
||||||
with mock.patch('neutron.agent.dhcp_agent.DhcpPluginApi') as plug:
|
with mock.patch('neutron.agent.dhcp_agent.DhcpPluginApi') as plug:
|
||||||
mock_plugin = mock.Mock()
|
mock_plugin = mock.Mock()
|
||||||
mock_plugin.get_active_networks.return_value = active_networks
|
mock_plugin.get_active_networks_info.return_value = active_networks
|
||||||
plug.return_value = mock_plugin
|
plug.return_value = mock_plugin
|
||||||
|
|
||||||
dhcp = dhcp_agent.DhcpAgent(HOSTNAME)
|
dhcp = dhcp_agent.DhcpAgent(HOSTNAME)
|
||||||
@ -298,7 +315,7 @@ class TestDhcpAgent(base.BaseTestCase):
|
|||||||
def test_sync_state_plugin_error(self):
|
def test_sync_state_plugin_error(self):
|
||||||
with mock.patch('neutron.agent.dhcp_agent.DhcpPluginApi') as plug:
|
with mock.patch('neutron.agent.dhcp_agent.DhcpPluginApi') as plug:
|
||||||
mock_plugin = mock.Mock()
|
mock_plugin = mock.Mock()
|
||||||
mock_plugin.get_active_networks.side_effect = Exception
|
mock_plugin.get_active_networks_info.side_effect = Exception
|
||||||
plug.return_value = mock_plugin
|
plug.return_value = mock_plugin
|
||||||
|
|
||||||
with mock.patch.object(dhcp_agent.LOG, 'exception') as log:
|
with mock.patch.object(dhcp_agent.LOG, 'exception') as log:
|
||||||
@ -781,12 +798,6 @@ class TestDhcpPluginApiProxy(base.BaseTestCase):
|
|||||||
self.call_p.stop()
|
self.call_p.stop()
|
||||||
super(TestDhcpPluginApiProxy, self).tearDown()
|
super(TestDhcpPluginApiProxy, self).tearDown()
|
||||||
|
|
||||||
def test_get_active_networks(self):
|
|
||||||
self.proxy.get_active_networks()
|
|
||||||
self.assertTrue(self.call.called)
|
|
||||||
self.make_msg.assert_called_once_with('get_active_networks',
|
|
||||||
host='foo')
|
|
||||||
|
|
||||||
def test_get_network_info(self):
|
def test_get_network_info(self):
|
||||||
self.call.return_value = dict(a=1)
|
self.call.return_value = dict(a=1)
|
||||||
retval = self.proxy.get_network_info('netid')
|
retval = self.proxy.get_network_info('netid')
|
||||||
@ -806,6 +817,34 @@ class TestDhcpPluginApiProxy(base.BaseTestCase):
|
|||||||
device_id='devid',
|
device_id='devid',
|
||||||
host='foo')
|
host='foo')
|
||||||
|
|
||||||
|
def test_get_active_networks_info(self):
|
||||||
|
self.proxy.get_active_networks_info()
|
||||||
|
self.make_msg.assert_called_once_with('get_active_networks_info',
|
||||||
|
host='foo')
|
||||||
|
|
||||||
|
def test_create_dhcp_port(self):
|
||||||
|
port_body = (
|
||||||
|
{'port':
|
||||||
|
{'name': '', 'admin_state_up': True,
|
||||||
|
'network_id': fake_network.id,
|
||||||
|
'tenant_id': fake_network.tenant_id,
|
||||||
|
'fixed_ips': [{'subnet_id': fake_fixed_ip1.subnet_id}],
|
||||||
|
'device_id': mock.ANY}})
|
||||||
|
|
||||||
|
self.proxy.create_dhcp_port(port_body)
|
||||||
|
self.make_msg.assert_called_once_with('create_dhcp_port',
|
||||||
|
port=port_body,
|
||||||
|
host='foo')
|
||||||
|
|
||||||
|
def test_update_dhcp_port(self):
|
||||||
|
port_body = {'port': {'fixed_ips':
|
||||||
|
[{'subnet_id': fake_fixed_ip1.subnet_id}]}}
|
||||||
|
self.proxy.update_dhcp_port(fake_port1.id, port_body)
|
||||||
|
self.make_msg.assert_called_once_with('update_dhcp_port',
|
||||||
|
port_id=fake_port1.id,
|
||||||
|
port=port_body,
|
||||||
|
host='foo')
|
||||||
|
|
||||||
def test_release_dhcp_port(self):
|
def test_release_dhcp_port(self):
|
||||||
self.proxy.release_dhcp_port('netid', 'devid')
|
self.proxy.release_dhcp_port('netid', 'devid')
|
||||||
self.assertTrue(self.call.called)
|
self.assertTrue(self.call.called)
|
||||||
@ -1019,6 +1058,7 @@ class TestDeviceManager(base.BaseTestCase):
|
|||||||
net = net or fake_network
|
net = net or fake_network
|
||||||
port = port or fake_port1
|
port = port or fake_port1
|
||||||
plugin = mock.Mock()
|
plugin = mock.Mock()
|
||||||
|
plugin.create_dhcp_port.return_value = port or fake_port1
|
||||||
plugin.get_dhcp_port.return_value = port or fake_port1
|
plugin.get_dhcp_port.return_value = port or fake_port1
|
||||||
self.device_exists.return_value = device_exists
|
self.device_exists.return_value = device_exists
|
||||||
self.mock_driver.get_device_name.return_value = 'tap12345678-12'
|
self.mock_driver.get_device_name.return_value = 'tap12345678-12'
|
||||||
@ -1030,7 +1070,12 @@ class TestDeviceManager(base.BaseTestCase):
|
|||||||
self.assertEqual(interface_name, 'tap12345678-12')
|
self.assertEqual(interface_name, 'tap12345678-12')
|
||||||
|
|
||||||
plugin.assert_has_calls([
|
plugin.assert_has_calls([
|
||||||
mock.call.get_dhcp_port(net.id, mock.ANY)])
|
mock.call.create_dhcp_port(
|
||||||
|
{'port': {'name': '', 'admin_state_up': True,
|
||||||
|
'network_id': net.id, 'tenant_id': net.tenant_id,
|
||||||
|
'fixed_ips':
|
||||||
|
[{'subnet_id': fake_fixed_ip1.subnet_id}],
|
||||||
|
'device_id': mock.ANY}})])
|
||||||
|
|
||||||
namespace = dhcp_agent.NS_PREFIX + net.id
|
namespace = dhcp_agent.NS_PREFIX + net.id
|
||||||
|
|
||||||
@ -1060,6 +1105,46 @@ class TestDeviceManager(base.BaseTestCase):
|
|||||||
def test_setup_device_exists_reuse(self):
|
def test_setup_device_exists_reuse(self):
|
||||||
self._test_setup_helper(True, True)
|
self._test_setup_helper(True, True)
|
||||||
|
|
||||||
|
def test_create_dhcp_port_create_new(self):
|
||||||
|
plugin = mock.Mock()
|
||||||
|
dh = dhcp_agent.DeviceManager(cfg.CONF, plugin)
|
||||||
|
plugin.create_dhcp_port.return_value = fake_network.ports[0]
|
||||||
|
dh.setup_dhcp_port(fake_network)
|
||||||
|
plugin.assert_has_calls([
|
||||||
|
mock.call.create_dhcp_port(
|
||||||
|
{'port': {'name': '', 'admin_state_up': True,
|
||||||
|
'network_id':
|
||||||
|
fake_network.id, 'tenant_id': fake_network.tenant_id,
|
||||||
|
'fixed_ips':
|
||||||
|
[{'subnet_id': fake_fixed_ip1.subnet_id}],
|
||||||
|
'device_id': mock.ANY}})])
|
||||||
|
|
||||||
|
def test_create_dhcp_port_update_add_subnet(self):
|
||||||
|
plugin = mock.Mock()
|
||||||
|
dh = dhcp_agent.DeviceManager(cfg.CONF, plugin)
|
||||||
|
fake_network_copy = copy.deepcopy(fake_network)
|
||||||
|
fake_network_copy.ports[0].device_id = dh.get_device_id(fake_network)
|
||||||
|
fake_network_copy.subnets[1].enable_dhcp = True
|
||||||
|
plugin.update_dhcp_port.return_value = fake_network.ports[0]
|
||||||
|
dh.setup_dhcp_port(fake_network_copy)
|
||||||
|
port_body = {'port': {
|
||||||
|
'fixed_ips': [{'subnet_id': fake_fixed_ip1.subnet_id,
|
||||||
|
'ip_address': fake_fixed_ip1.ip_address},
|
||||||
|
{'subnet_id': fake_subnet2.id}]}}
|
||||||
|
|
||||||
|
plugin.assert_has_calls([
|
||||||
|
mock.call.update_dhcp_port(fake_network_copy.ports[0].id,
|
||||||
|
port_body)])
|
||||||
|
|
||||||
|
def test_create_dhcp_port_no_update_or_create(self):
|
||||||
|
plugin = mock.Mock()
|
||||||
|
dh = dhcp_agent.DeviceManager(cfg.CONF, plugin)
|
||||||
|
fake_network_copy = copy.deepcopy(fake_network)
|
||||||
|
fake_network_copy.ports[0].device_id = dh.get_device_id(fake_network)
|
||||||
|
dh.setup_dhcp_port(fake_network_copy)
|
||||||
|
self.assertFalse(plugin.setup_dhcp_port.called)
|
||||||
|
self.assertFalse(plugin.update_dhcp_port.called)
|
||||||
|
|
||||||
def test_destroy(self):
|
def test_destroy(self):
|
||||||
fake_network = FakeModel('12345678-1234-5678-1234567890ab',
|
fake_network = FakeModel('12345678-1234-5678-1234567890ab',
|
||||||
tenant_id='aaaaaaaa-aaaa-aaaa-aaaaaaaaaaaa')
|
tenant_id='aaaaaaaa-aaaa-aaaa-aaaaaaaaaaaa')
|
||||||
@ -1069,9 +1154,6 @@ class TestDeviceManager(base.BaseTestCase):
|
|||||||
|
|
||||||
with mock.patch('neutron.agent.linux.interface.NullDriver') as dvr_cls:
|
with mock.patch('neutron.agent.linux.interface.NullDriver') as dvr_cls:
|
||||||
mock_driver = mock.MagicMock()
|
mock_driver = mock.MagicMock()
|
||||||
#mock_driver.DEV_NAME_LEN = (
|
|
||||||
# interface.LinuxInterfaceDriver.DEV_NAME_LEN)
|
|
||||||
#mock_driver.port = fake_port
|
|
||||||
mock_driver.get_device_name.return_value = 'tap12345678-12'
|
mock_driver.get_device_name.return_value = 'tap12345678-12'
|
||||||
dvr_cls.return_value = mock_driver
|
dvr_cls.return_value = mock_driver
|
||||||
|
|
||||||
@ -1112,31 +1194,6 @@ class TestDeviceManager(base.BaseTestCase):
|
|||||||
|
|
||||||
self.assertEqual(len(plugin.mock_calls), 0)
|
self.assertEqual(len(plugin.mock_calls), 0)
|
||||||
|
|
||||||
def test_get_interface_name_no_port_provided(self):
|
|
||||||
fake_network = FakeModel('12345678-1234-5678-1234567890ab',
|
|
||||||
tenant_id='aaaaaaaa-aaaa-aaaa-aaaaaaaaaaaa')
|
|
||||||
|
|
||||||
fake_port = FakeModel('12345678-1234-aaaa-1234567890ab',
|
|
||||||
mac_address='aa:bb:cc:dd:ee:ff')
|
|
||||||
|
|
||||||
with mock.patch('neutron.agent.linux.interface.NullDriver') as dvr_cls:
|
|
||||||
mock_driver = mock.MagicMock()
|
|
||||||
mock_driver.get_device_name.return_value = 'tap12345678-12'
|
|
||||||
dvr_cls.return_value = mock_driver
|
|
||||||
|
|
||||||
plugin = mock.Mock()
|
|
||||||
plugin.get_dhcp_port.return_value = fake_port
|
|
||||||
|
|
||||||
dh = dhcp_agent.DeviceManager(cfg.CONF, plugin)
|
|
||||||
dh.get_interface_name(fake_network)
|
|
||||||
|
|
||||||
dvr_cls.assert_called_once_with(cfg.CONF)
|
|
||||||
mock_driver.assert_has_calls(
|
|
||||||
[mock.call.get_device_name(fake_port)])
|
|
||||||
|
|
||||||
plugin.assert_has_calls(
|
|
||||||
[mock.call.get_dhcp_port(fake_network.id, mock.ANY)])
|
|
||||||
|
|
||||||
def test_get_device_id(self):
|
def test_get_device_id(self):
|
||||||
fake_network = FakeModel('12345678-1234-5678-1234567890ab',
|
fake_network = FakeModel('12345678-1234-5678-1234567890ab',
|
||||||
tenant_id='aaaaaaaa-aaaa-aaaa-aaaaaaaaaaaa')
|
tenant_id='aaaaaaaa-aaaa-aaaa-aaaaaaaaaaaa')
|
||||||
|
Loading…
Reference in New Issue
Block a user