Merge "Remove DHCP lease logic"
This commit is contained in:
commit
436e25f957
@ -1,20 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
|
||||||
|
|
||||||
# Copyright (c) 2012 OpenStack Foundation.
|
|
||||||
# All Rights Reserved.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
from neutron.agent.linux import dhcp
|
|
||||||
dhcp.Dnsmasq.lease_update()
|
|
@ -69,7 +69,7 @@ lock_path = $state_path/lock
|
|||||||
# mac_generation_retries = 16
|
# mac_generation_retries = 16
|
||||||
|
|
||||||
# DHCP Lease duration (in seconds)
|
# DHCP Lease duration (in seconds)
|
||||||
# dhcp_lease_duration = 120
|
# dhcp_lease_duration = 86400
|
||||||
|
|
||||||
# Allow sending resource operation notification to DHCP agent
|
# Allow sending resource operation notification to DHCP agent
|
||||||
# dhcp_agent_notification = True
|
# dhcp_agent_notification = True
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
[Filters]
|
[Filters]
|
||||||
|
|
||||||
# dhcp-agent
|
# dhcp-agent
|
||||||
dnsmasq: EnvFilter, dnsmasq, root, NEUTRON_RELAY_SOCKET_PATH=, NEUTRON_NETWORK_ID=
|
dnsmasq: EnvFilter, dnsmasq, root, NEUTRON_NETWORK_ID=
|
||||||
# dhcp-agent uses kill as well, that's handled by the generic KillFilter
|
# dhcp-agent uses kill as well, that's handled by the generic KillFilter
|
||||||
# it looks like these are the only signals needed, per
|
# it looks like these are the only signals needed, per
|
||||||
# neutron/agent/linux/dhcp.py
|
# neutron/agent/linux/dhcp.py
|
||||||
@ -20,6 +20,7 @@ kill_dnsmasq_usr: KillFilter, root, /usr/sbin/dnsmasq, -9, -HUP
|
|||||||
cat: RegExpFilter, cat, root, cat, /proc/\d+/cmdline
|
cat: RegExpFilter, cat, root, cat, /proc/\d+/cmdline
|
||||||
ovs-vsctl: CommandFilter, ovs-vsctl, root
|
ovs-vsctl: CommandFilter, ovs-vsctl, root
|
||||||
ivs-ctl: CommandFilter, ivs-ctl, root
|
ivs-ctl: CommandFilter, ivs-ctl, root
|
||||||
|
dhcp_release: CommandFilter, dhcp_release, root
|
||||||
|
|
||||||
# metadata proxy
|
# metadata proxy
|
||||||
metadata_proxy: CommandFilter, neutron-ns-metadata-proxy, root
|
metadata_proxy: CommandFilter, neutron-ns-metadata-proxy, root
|
||||||
|
@ -37,12 +37,10 @@ from neutron.common import utils
|
|||||||
from neutron import context
|
from neutron import context
|
||||||
from neutron import manager
|
from neutron import manager
|
||||||
from neutron.openstack.common import importutils
|
from neutron.openstack.common import importutils
|
||||||
from neutron.openstack.common import jsonutils
|
|
||||||
from neutron.openstack.common import log as logging
|
from neutron.openstack.common import log as logging
|
||||||
from neutron.openstack.common import loopingcall
|
from neutron.openstack.common import loopingcall
|
||||||
from neutron.openstack.common.rpc import proxy
|
from neutron.openstack.common.rpc import proxy
|
||||||
from neutron.openstack.common import service
|
from neutron.openstack.common import service
|
||||||
from neutron.openstack.common import uuidutils
|
|
||||||
from neutron import service as neutron_service
|
from neutron import service as neutron_service
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
@ -81,8 +79,10 @@ class DhcpAgent(manager.Manager):
|
|||||||
ctx = context.get_admin_context_without_session()
|
ctx = context.get_admin_context_without_session()
|
||||||
self.plugin_rpc = DhcpPluginApi(topics.PLUGIN, ctx)
|
self.plugin_rpc = DhcpPluginApi(topics.PLUGIN, ctx)
|
||||||
self.device_manager = DeviceManager(self.conf, self.plugin_rpc)
|
self.device_manager = DeviceManager(self.conf, self.plugin_rpc)
|
||||||
self.lease_relay = DhcpLeaseRelay(self.update_lease)
|
# create dhcp dir to store dhcp info
|
||||||
|
dhcp_dir = os.path.dirname("/%s/dhcp/" % self.conf.state_path)
|
||||||
|
if not os.path.isdir(dhcp_dir):
|
||||||
|
os.makedirs(dhcp_dir, 0o755)
|
||||||
self.dhcp_version = self.dhcp_driver_cls.check_version()
|
self.dhcp_version = self.dhcp_driver_cls.check_version()
|
||||||
self._populate_networks_cache()
|
self._populate_networks_cache()
|
||||||
|
|
||||||
@ -114,13 +114,12 @@ class DhcpAgent(manager.Manager):
|
|||||||
"""Activate the DHCP agent."""
|
"""Activate the DHCP agent."""
|
||||||
self.sync_state()
|
self.sync_state()
|
||||||
self.periodic_resync()
|
self.periodic_resync()
|
||||||
self.lease_relay.start()
|
|
||||||
|
|
||||||
def _ns_name(self, network):
|
def _ns_name(self, network):
|
||||||
if self.conf.use_namespaces:
|
if self.conf.use_namespaces:
|
||||||
return NS_PREFIX + network.id
|
return NS_PREFIX + network.id
|
||||||
|
|
||||||
def call_driver(self, action, network):
|
def call_driver(self, action, network, **action_kwargs):
|
||||||
"""Invoke an action on a DHCP driver instance."""
|
"""Invoke an action on a DHCP driver instance."""
|
||||||
try:
|
try:
|
||||||
# the Driver expects something that is duck typed similar to
|
# the Driver expects something that is duck typed similar to
|
||||||
@ -131,21 +130,13 @@ class DhcpAgent(manager.Manager):
|
|||||||
self.device_manager,
|
self.device_manager,
|
||||||
self._ns_name(network),
|
self._ns_name(network),
|
||||||
self.dhcp_version)
|
self.dhcp_version)
|
||||||
getattr(driver, action)()
|
getattr(driver, action)(**action_kwargs)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
self.needs_resync = True
|
self.needs_resync = True
|
||||||
LOG.exception(_('Unable to %s dhcp.'), action)
|
LOG.exception(_('Unable to %s dhcp.'), action)
|
||||||
|
|
||||||
def update_lease(self, network_id, ip_address, time_remaining):
|
|
||||||
try:
|
|
||||||
self.plugin_rpc.update_lease_expiration(network_id, ip_address,
|
|
||||||
time_remaining)
|
|
||||||
except Exception:
|
|
||||||
self.needs_resync = True
|
|
||||||
LOG.exception(_('Unable to update lease'))
|
|
||||||
|
|
||||||
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'))
|
||||||
@ -246,6 +237,22 @@ class DhcpAgent(manager.Manager):
|
|||||||
if new_cidrs:
|
if new_cidrs:
|
||||||
self.device_manager.update(network)
|
self.device_manager.update(network)
|
||||||
|
|
||||||
|
def release_lease_for_removed_ips(self, port, network):
|
||||||
|
"""Releases the dhcp lease for ips removed from a port."""
|
||||||
|
prev_port = self.cache.get_port_by_id(port.id)
|
||||||
|
if prev_port:
|
||||||
|
previous_ips = set(fixed_ip.ip_address
|
||||||
|
for fixed_ip in prev_port.fixed_ips)
|
||||||
|
current_ips = set(fixed_ip.ip_address
|
||||||
|
for fixed_ip in port.fixed_ips)
|
||||||
|
# pass in port with removed ips on it
|
||||||
|
removed_ips = previous_ips - current_ips
|
||||||
|
if removed_ips:
|
||||||
|
self.call_driver('release_lease',
|
||||||
|
network,
|
||||||
|
mac_address=port.mac_address,
|
||||||
|
removed_ips=removed_ips)
|
||||||
|
|
||||||
@utils.synchronized('dhcp-agent')
|
@utils.synchronized('dhcp-agent')
|
||||||
def network_create_end(self, context, payload):
|
def network_create_end(self, context, payload):
|
||||||
"""Handle the network.create.end notification event."""
|
"""Handle the network.create.end notification event."""
|
||||||
@ -289,6 +296,7 @@ class DhcpAgent(manager.Manager):
|
|||||||
port = DictModel(payload['port'])
|
port = DictModel(payload['port'])
|
||||||
network = self.cache.get_network_by_id(port.network_id)
|
network = self.cache.get_network_by_id(port.network_id)
|
||||||
if network:
|
if network:
|
||||||
|
self.release_lease_for_removed_ips(port, network)
|
||||||
self.cache.put_port(port)
|
self.cache.put_port(port)
|
||||||
self.call_driver('reload_allocations', network)
|
self.call_driver('reload_allocations', network)
|
||||||
|
|
||||||
@ -302,6 +310,12 @@ class DhcpAgent(manager.Manager):
|
|||||||
if port:
|
if port:
|
||||||
network = self.cache.get_network_by_id(port.network_id)
|
network = self.cache.get_network_by_id(port.network_id)
|
||||||
self.cache.remove_port(port)
|
self.cache.remove_port(port)
|
||||||
|
removed_ips = [fixed_ip.ip_address
|
||||||
|
for fixed_ip in port.fixed_ips]
|
||||||
|
self.call_driver('release_lease',
|
||||||
|
network,
|
||||||
|
mac_address=port.mac_address,
|
||||||
|
removed_ips=removed_ips)
|
||||||
self.call_driver('reload_allocations', network)
|
self.call_driver('reload_allocations', network)
|
||||||
|
|
||||||
def enable_isolated_metadata_proxy(self, network):
|
def enable_isolated_metadata_proxy(self, network):
|
||||||
@ -435,16 +449,6 @@ class DhcpPluginApi(proxy.RpcProxy):
|
|||||||
host=self.host),
|
host=self.host),
|
||||||
topic=self.topic)
|
topic=self.topic)
|
||||||
|
|
||||||
def update_lease_expiration(self, network_id, ip_address, lease_remaining):
|
|
||||||
"""Make a remote process call to update the ip lease expiration."""
|
|
||||||
self.cast(self.context,
|
|
||||||
self.make_msg('update_lease_expiration',
|
|
||||||
network_id=network_id,
|
|
||||||
ip_address=ip_address,
|
|
||||||
lease_remaining=lease_remaining,
|
|
||||||
host=self.host),
|
|
||||||
topic=self.topic)
|
|
||||||
|
|
||||||
|
|
||||||
class NetworkCache(object):
|
class NetworkCache(object):
|
||||||
"""Agent cache of the current network state."""
|
"""Agent cache of the current network state."""
|
||||||
@ -747,67 +751,6 @@ class DictModel(object):
|
|||||||
setattr(self, key, value)
|
setattr(self, key, value)
|
||||||
|
|
||||||
|
|
||||||
class DhcpLeaseRelay(object):
|
|
||||||
"""UNIX domain socket server for processing lease updates.
|
|
||||||
|
|
||||||
Network namespace isolation prevents the DHCP process from notifying
|
|
||||||
Neutron directly. This class works around the limitation by using the
|
|
||||||
domain socket to pass the information. This class handles message.
|
|
||||||
receiving and then calls the callback method.
|
|
||||||
"""
|
|
||||||
|
|
||||||
OPTS = [
|
|
||||||
cfg.StrOpt('dhcp_lease_relay_socket',
|
|
||||||
default='$state_path/dhcp/lease_relay',
|
|
||||||
help=_('Location to DHCP lease relay UNIX domain socket'))
|
|
||||||
]
|
|
||||||
|
|
||||||
def __init__(self, lease_update_callback):
|
|
||||||
self.callback = lease_update_callback
|
|
||||||
|
|
||||||
dirname = os.path.dirname(cfg.CONF.dhcp_lease_relay_socket)
|
|
||||||
if os.path.isdir(dirname):
|
|
||||||
try:
|
|
||||||
os.unlink(cfg.CONF.dhcp_lease_relay_socket)
|
|
||||||
except OSError:
|
|
||||||
if os.path.exists(cfg.CONF.dhcp_lease_relay_socket):
|
|
||||||
raise
|
|
||||||
else:
|
|
||||||
os.makedirs(dirname, 0o755)
|
|
||||||
|
|
||||||
def _handler(self, client_sock, client_addr):
|
|
||||||
"""Handle incoming lease relay stream connection.
|
|
||||||
|
|
||||||
This method will only read the first 1024 bytes and then close the
|
|
||||||
connection. The limit exists to limit the impact of misbehaving
|
|
||||||
clients.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
msg = client_sock.recv(1024)
|
|
||||||
data = jsonutils.loads(msg)
|
|
||||||
client_sock.close()
|
|
||||||
|
|
||||||
network_id = data['network_id']
|
|
||||||
if not uuidutils.is_uuid_like(network_id):
|
|
||||||
raise ValueError(_("Network ID %s is not a valid UUID") %
|
|
||||||
network_id)
|
|
||||||
ip_address = str(netaddr.IPAddress(data['ip_address']))
|
|
||||||
lease_remaining = int(data['lease_remaining'])
|
|
||||||
self.callback(network_id, ip_address, lease_remaining)
|
|
||||||
except ValueError as e:
|
|
||||||
LOG.warn(_('Unable to parse lease relay msg to dict.'))
|
|
||||||
LOG.warn(_('Exception value: %s'), e)
|
|
||||||
LOG.warn(_('Message representation: %s'), repr(msg))
|
|
||||||
except Exception as e:
|
|
||||||
LOG.exception(_('Unable update lease. Exception'))
|
|
||||||
|
|
||||||
def start(self):
|
|
||||||
"""Spawn a green thread to run the lease relay unix socket server."""
|
|
||||||
listener = eventlet.listen(cfg.CONF.dhcp_lease_relay_socket,
|
|
||||||
family=socket.AF_UNIX)
|
|
||||||
eventlet.spawn(eventlet.serve, listener, self._handler)
|
|
||||||
|
|
||||||
|
|
||||||
class DhcpAgentWithStateReport(DhcpAgent):
|
class DhcpAgentWithStateReport(DhcpAgent):
|
||||||
def __init__(self, host=None):
|
def __init__(self, host=None):
|
||||||
super(DhcpAgentWithStateReport, self).__init__(host=host)
|
super(DhcpAgentWithStateReport, self).__init__(host=host)
|
||||||
@ -863,7 +806,6 @@ def register_options():
|
|||||||
config.register_agent_state_opts_helper(cfg.CONF)
|
config.register_agent_state_opts_helper(cfg.CONF)
|
||||||
config.register_root_helper(cfg.CONF)
|
config.register_root_helper(cfg.CONF)
|
||||||
cfg.CONF.register_opts(DeviceManager.OPTS)
|
cfg.CONF.register_opts(DeviceManager.OPTS)
|
||||||
cfg.CONF.register_opts(DhcpLeaseRelay.OPTS)
|
|
||||||
cfg.CONF.register_opts(dhcp.OPTS)
|
cfg.CONF.register_opts(dhcp.OPTS)
|
||||||
cfg.CONF.register_opts(interface.OPTS)
|
cfg.CONF.register_opts(interface.OPTS)
|
||||||
|
|
||||||
|
@ -89,6 +89,10 @@ class DhcpBase(object):
|
|||||||
def active(self):
|
def active(self):
|
||||||
"""Boolean representing the running state of the DHCP server."""
|
"""Boolean representing the running state of the DHCP server."""
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def release_lease(self, mac_address, removed_ips):
|
||||||
|
"""Release a DHCP lease."""
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def reload_allocations(self):
|
def reload_allocations(self):
|
||||||
"""Force the DHCP server to reload the assignment database."""
|
"""Force the DHCP server to reload the assignment database."""
|
||||||
@ -261,8 +265,6 @@ class Dnsmasq(DhcpLocalProcess):
|
|||||||
"""Spawns a Dnsmasq process for the network."""
|
"""Spawns a Dnsmasq process for the network."""
|
||||||
env = {
|
env = {
|
||||||
self.NEUTRON_NETWORK_ID_KEY: self.network.id,
|
self.NEUTRON_NETWORK_ID_KEY: self.network.id,
|
||||||
self.NEUTRON_RELAY_SOCKET_PATH_KEY:
|
|
||||||
self.conf.dhcp_lease_relay_socket
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd = [
|
cmd = [
|
||||||
@ -279,7 +281,6 @@ class Dnsmasq(DhcpLocalProcess):
|
|||||||
#'--dhcp-lease-max=%s' % ?,
|
#'--dhcp-lease-max=%s' % ?,
|
||||||
'--dhcp-hostsfile=%s' % self._output_hosts_file(),
|
'--dhcp-hostsfile=%s' % self._output_hosts_file(),
|
||||||
'--dhcp-optsfile=%s' % self._output_opts_file(),
|
'--dhcp-optsfile=%s' % self._output_opts_file(),
|
||||||
'--dhcp-script=%s' % self._lease_relay_script_path(),
|
|
||||||
'--leasefile-ro',
|
'--leasefile-ro',
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -318,6 +319,16 @@ class Dnsmasq(DhcpLocalProcess):
|
|||||||
cmd = ['%s=%s' % pair for pair in env.items()] + cmd
|
cmd = ['%s=%s' % pair for pair in env.items()] + cmd
|
||||||
utils.execute(cmd, self.root_helper)
|
utils.execute(cmd, self.root_helper)
|
||||||
|
|
||||||
|
def release_lease(self, mac_address, removed_ips):
|
||||||
|
"""Release a DHCP lease."""
|
||||||
|
for ip in removed_ips or []:
|
||||||
|
cmd = ['dhcp_release', self.interface_name, ip, mac_address]
|
||||||
|
if self.namespace:
|
||||||
|
ip_wrapper = ip_lib.IPWrapper(self.root_helper, self.namespace)
|
||||||
|
ip_wrapper.netns.execute(cmd)
|
||||||
|
else:
|
||||||
|
utils.execute(cmd, self.root_helper)
|
||||||
|
|
||||||
def reload_allocations(self):
|
def reload_allocations(self):
|
||||||
"""Rebuild the dnsmasq config and signal the dnsmasq to reload."""
|
"""Rebuild the dnsmasq config and signal the dnsmasq to reload."""
|
||||||
|
|
||||||
@ -428,10 +439,6 @@ class Dnsmasq(DhcpLocalProcess):
|
|||||||
|
|
||||||
return retval
|
return retval
|
||||||
|
|
||||||
def _lease_relay_script_path(self):
|
|
||||||
return os.path.join(os.path.dirname(sys.argv[0]),
|
|
||||||
'neutron-dhcp-agent-dnsmasq-lease-update')
|
|
||||||
|
|
||||||
def _format_option(self, index, option, *args):
|
def _format_option(self, index, option, *args):
|
||||||
"""Format DHCP option by option name or code."""
|
"""Format DHCP option by option name or code."""
|
||||||
if self.version >= self.MINIMUM_VERSION:
|
if self.version >= self.MINIMUM_VERSION:
|
||||||
|
@ -71,7 +71,7 @@ core_opts = [
|
|||||||
help=_("Maximum number of host routes per subnet")),
|
help=_("Maximum number of host routes per subnet")),
|
||||||
cfg.IntOpt('max_fixed_ips_per_port', default=5,
|
cfg.IntOpt('max_fixed_ips_per_port', default=5,
|
||||||
help=_("Maximum number of fixed ips per port")),
|
help=_("Maximum number of fixed ips per port")),
|
||||||
cfg.IntOpt('dhcp_lease_duration', default=120,
|
cfg.IntOpt('dhcp_lease_duration', default=86400,
|
||||||
deprecated_name='dhcp_lease_time',
|
deprecated_name='dhcp_lease_time',
|
||||||
help=_("DHCP lease duration")),
|
help=_("DHCP lease duration")),
|
||||||
cfg.BoolOpt('dhcp_agent_notification', default=True,
|
cfg.BoolOpt('dhcp_agent_notification', default=True,
|
||||||
|
@ -293,54 +293,6 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _hold_ip(context, network_id, subnet_id, port_id, ip_address):
|
|
||||||
alloc_qry = context.session.query(
|
|
||||||
models_v2.IPAllocation).with_lockmode('update')
|
|
||||||
allocated = alloc_qry.filter_by(network_id=network_id,
|
|
||||||
port_id=port_id,
|
|
||||||
ip_address=ip_address,
|
|
||||||
subnet_id=subnet_id).one()
|
|
||||||
|
|
||||||
if not allocated:
|
|
||||||
return
|
|
||||||
if allocated.expiration < timeutils.utcnow():
|
|
||||||
# immediately delete expired allocations
|
|
||||||
NeutronDbPluginV2._recycle_ip(
|
|
||||||
context, network_id, subnet_id, ip_address)
|
|
||||||
else:
|
|
||||||
LOG.debug(_("Hold allocated IP %(ip_address)s "
|
|
||||||
"(%(network_id)s/%(subnet_id)s/%(port_id)s)"),
|
|
||||||
{'ip_address': ip_address,
|
|
||||||
'network_id': network_id,
|
|
||||||
'subnet_id': subnet_id,
|
|
||||||
'port_id': port_id})
|
|
||||||
allocated.port_id = None
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _recycle_expired_ip_allocations(context, network_id):
|
|
||||||
"""Return held ip allocations with expired leases back to the pool."""
|
|
||||||
if network_id in getattr(context, '_recycled_networks', set()):
|
|
||||||
return
|
|
||||||
|
|
||||||
expired_qry = context.session.query(
|
|
||||||
models_v2.IPAllocation).with_lockmode('update')
|
|
||||||
expired_qry = expired_qry.filter_by(network_id=network_id,
|
|
||||||
port_id=None)
|
|
||||||
expired_qry = expired_qry.filter(
|
|
||||||
models_v2.IPAllocation.expiration <= timeutils.utcnow())
|
|
||||||
|
|
||||||
for expired in expired_qry:
|
|
||||||
NeutronDbPluginV2._recycle_ip(context,
|
|
||||||
network_id,
|
|
||||||
expired['subnet_id'],
|
|
||||||
expired['ip_address'])
|
|
||||||
|
|
||||||
if hasattr(context, '_recycled_networks'):
|
|
||||||
context._recycled_networks.add(network_id)
|
|
||||||
else:
|
|
||||||
context._recycled_networks = set([network_id])
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _recycle_ip(context, network_id, subnet_id, ip_address):
|
def _recycle_ip(context, network_id, subnet_id, ip_address):
|
||||||
"""Return an IP address to the pool of free IP's on the network
|
"""Return an IP address to the pool of free IP's on the network
|
||||||
@ -424,11 +376,6 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
|
|||||||
NeutronDbPluginV2._delete_ip_allocation(context, network_id, subnet_id,
|
NeutronDbPluginV2._delete_ip_allocation(context, network_id, subnet_id,
|
||||||
ip_address)
|
ip_address)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _default_allocation_expiration():
|
|
||||||
return (timeutils.utcnow() +
|
|
||||||
datetime.timedelta(seconds=cfg.CONF.dhcp_lease_duration))
|
|
||||||
|
|
||||||
def update_fixed_ip_lease_expiration(self, context, network_id,
|
def update_fixed_ip_lease_expiration(self, context, network_id,
|
||||||
ip_address, lease_remaining):
|
ip_address, lease_remaining):
|
||||||
|
|
||||||
@ -690,10 +637,9 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
|
|||||||
to_add = self._test_fixed_ips_for_port(context, network_id, new_ips)
|
to_add = self._test_fixed_ips_for_port(context, network_id, new_ips)
|
||||||
for ip in original_ips:
|
for ip in original_ips:
|
||||||
LOG.debug(_("Port update. Hold %s"), ip)
|
LOG.debug(_("Port update. Hold %s"), ip)
|
||||||
NeutronDbPluginV2._hold_ip(context,
|
NeutronDbPluginV2._recycle_ip(context,
|
||||||
network_id,
|
network_id,
|
||||||
ip['subnet_id'],
|
ip['subnet_id'],
|
||||||
port_id,
|
|
||||||
ip['ip_address'])
|
ip['ip_address'])
|
||||||
|
|
||||||
if to_add:
|
if to_add:
|
||||||
@ -1321,7 +1267,6 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
|
|||||||
tenant_id = self._get_tenant_id_for_create(context, p)
|
tenant_id = self._get_tenant_id_for_create(context, p)
|
||||||
|
|
||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
self._recycle_expired_ip_allocations(context, network_id)
|
|
||||||
network = self._get_network(context, network_id)
|
network = self._get_network(context, network_id)
|
||||||
|
|
||||||
# Ensure that a MAC address is defined and it is unique on the
|
# Ensure that a MAC address is defined and it is unique on the
|
||||||
@ -1372,7 +1317,6 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
|
|||||||
port_id=port_id,
|
port_id=port_id,
|
||||||
ip_address=ip_address,
|
ip_address=ip_address,
|
||||||
subnet_id=subnet_id,
|
subnet_id=subnet_id,
|
||||||
expiration=self._default_allocation_expiration()
|
|
||||||
)
|
)
|
||||||
context.session.add(allocated)
|
context.session.add(allocated)
|
||||||
|
|
||||||
@ -1387,8 +1331,6 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
|
|||||||
# Check if the IPs need to be updated
|
# Check if the IPs need to be updated
|
||||||
if 'fixed_ips' in p:
|
if 'fixed_ips' in p:
|
||||||
changed_ips = True
|
changed_ips = True
|
||||||
self._recycle_expired_ip_allocations(context,
|
|
||||||
port['network_id'])
|
|
||||||
original = self._make_port_dict(port, process_extensions=False)
|
original = self._make_port_dict(port, process_extensions=False)
|
||||||
added_ips, prev_ips = self._update_ips_for_port(
|
added_ips, prev_ips = self._update_ips_for_port(
|
||||||
context, port["network_id"], id, original["fixed_ips"],
|
context, port["network_id"], id, original["fixed_ips"],
|
||||||
@ -1398,8 +1340,7 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
|
|||||||
for ip in added_ips:
|
for ip in added_ips:
|
||||||
allocated = models_v2.IPAllocation(
|
allocated = models_v2.IPAllocation(
|
||||||
network_id=port['network_id'], port_id=port.id,
|
network_id=port['network_id'], port_id=port.id,
|
||||||
ip_address=ip['ip_address'], subnet_id=ip['subnet_id'],
|
ip_address=ip['ip_address'], subnet_id=ip['subnet_id'])
|
||||||
expiration=self._default_allocation_expiration())
|
|
||||||
context.session.add(allocated)
|
context.session.add(allocated)
|
||||||
# Remove all attributes in p which are not in the port DB model
|
# Remove all attributes in p which are not in the port DB model
|
||||||
# and then update the port
|
# and then update the port
|
||||||
@ -1428,10 +1369,9 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
|
|||||||
if NeutronDbPluginV2._check_ip_in_allocation_pool(
|
if NeutronDbPluginV2._check_ip_in_allocation_pool(
|
||||||
context, a['subnet_id'], subnet['gateway_ip'],
|
context, a['subnet_id'], subnet['gateway_ip'],
|
||||||
a['ip_address']):
|
a['ip_address']):
|
||||||
NeutronDbPluginV2._hold_ip(context,
|
NeutronDbPluginV2._recycle_ip(context,
|
||||||
a['network_id'],
|
a['network_id'],
|
||||||
a['subnet_id'],
|
a['subnet_id'],
|
||||||
id,
|
|
||||||
a['ip_address'])
|
a['ip_address'])
|
||||||
else:
|
else:
|
||||||
# IPs out of allocation pool will not be recycled, but
|
# IPs out of allocation pool will not be recycled, but
|
||||||
|
@ -47,8 +47,8 @@ class DhcpRpcCallbackMixin(object):
|
|||||||
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 network ids."""
|
||||||
# NOTE(arosen): This method is no longer used by the DHCP agent but is
|
# 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
|
# left so that neutron-dhcp-agents will still continue to work if
|
||||||
# quantum-server is upgraded and not the agent.
|
# neutron-server is upgraded and not the agent.
|
||||||
host = kwargs.get('host')
|
host = kwargs.get('host')
|
||||||
LOG.debug(_('get_active_networks requested from %s'), host)
|
LOG.debug(_('get_active_networks requested from %s'), host)
|
||||||
nets = self._get_active_networks(context, **kwargs)
|
nets = self._get_active_networks(context, **kwargs)
|
||||||
@ -97,8 +97,8 @@ class DhcpRpcCallbackMixin(object):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
# NOTE(arosen): This method is no longer used by the DHCP agent but is
|
# 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
|
# left so that neutron-dhcp-agents will still continue to work if
|
||||||
# quantum-server is upgraded and not the agent.
|
# neutron-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')
|
||||||
@ -209,20 +209,13 @@ class DhcpRpcCallbackMixin(object):
|
|||||||
|
|
||||||
def update_lease_expiration(self, context, **kwargs):
|
def update_lease_expiration(self, context, **kwargs):
|
||||||
"""Release the fixed_ip associated the subnet on a port."""
|
"""Release the fixed_ip associated the subnet on a port."""
|
||||||
|
# NOTE(arosen): This method is no longer used by the DHCP agent but is
|
||||||
|
# left so that neutron-dhcp-agents will still continue to work if
|
||||||
|
# neutron-server is upgraded and not the agent.
|
||||||
host = kwargs.get('host')
|
host = kwargs.get('host')
|
||||||
network_id = kwargs.get('network_id')
|
|
||||||
ip_address = kwargs.get('ip_address')
|
|
||||||
lease_remaining = kwargs.get('lease_remaining')
|
|
||||||
|
|
||||||
LOG.debug(_('Updating lease expiration for %(ip_address)s on network '
|
LOG.warning(_('Updating lease expiration is now deprecated. Issued '
|
||||||
'%(network_id)s from %(host)s.'),
|
'from host %(host)s.') % host)
|
||||||
{'ip_address': ip_address,
|
|
||||||
'network_id': network_id,
|
|
||||||
'host': host})
|
|
||||||
plugin = manager.NeutronManager.get_plugin()
|
|
||||||
|
|
||||||
plugin.update_fixed_ip_lease_expiration(context, network_id,
|
|
||||||
ip_address, lease_remaining)
|
|
||||||
|
|
||||||
def create_dhcp_port(self, context, **kwargs):
|
def create_dhcp_port(self, context, **kwargs):
|
||||||
"""Create the dhcp port."""
|
"""Create the dhcp port."""
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
#
|
||||||
|
# Copyright 2013 OpenStack Foundation
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
"""remove_dhcp_lease
|
||||||
|
|
||||||
|
Revision ID: f9263d6df56
|
||||||
|
Revises: c88b6b5fea3
|
||||||
|
Create Date: 2013-07-17 12:31:33.731197
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'f9263d6df56'
|
||||||
|
down_revision = 'c88b6b5fea3'
|
||||||
|
|
||||||
|
# Change to ['*'] if this migration applies to all plugins
|
||||||
|
|
||||||
|
migration_for_plugins = [
|
||||||
|
'*'
|
||||||
|
]
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade(active_plugins=None, options=None):
|
||||||
|
op.drop_column('ipallocations', u'expiration')
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade(active_plugins=None, options=None):
|
||||||
|
op.add_column('ipallocations', sa.Column(u'expiration', sa.DATETIME(),
|
||||||
|
nullable=True))
|
@ -99,7 +99,6 @@ class IPAllocation(model_base.BASEV2):
|
|||||||
network_id = sa.Column(sa.String(36), sa.ForeignKey("networks.id",
|
network_id = sa.Column(sa.String(36), sa.ForeignKey("networks.id",
|
||||||
ondelete="CASCADE"),
|
ondelete="CASCADE"),
|
||||||
nullable=False, primary_key=True)
|
nullable=False, primary_key=True)
|
||||||
expiration = sa.Column(sa.DateTime, nullable=True)
|
|
||||||
|
|
||||||
|
|
||||||
class Route(object):
|
class Route(object):
|
||||||
|
@ -41,6 +41,6 @@ class ConfigurationTest(base.BaseTestCase):
|
|||||||
'..', '..', '..')
|
'..', '..', '..')
|
||||||
absolute_dir = os.path.abspath(relative_dir)
|
absolute_dir = os.path.abspath(relative_dir)
|
||||||
self.assertEqual(absolute_dir, cfg.CONF.state_path)
|
self.assertEqual(absolute_dir, cfg.CONF.state_path)
|
||||||
self.assertEqual(120, cfg.CONF.dhcp_lease_duration)
|
self.assertEqual(86400, cfg.CONF.dhcp_lease_duration)
|
||||||
self.assertFalse(cfg.CONF.allow_overlapping_ips)
|
self.assertFalse(cfg.CONF.allow_overlapping_ips)
|
||||||
self.assertEqual('neutron', cfg.CONF.control_exchange)
|
self.assertEqual('neutron', cfg.CONF.control_exchange)
|
||||||
|
@ -1191,7 +1191,7 @@ fixed_ips=ip_address%%3D%s&fixed_ips=ip_address%%3D%s&fixed_ips=subnet_id%%3D%s
|
|||||||
self.assertEqual(ips[1]['subnet_id'], subnet['subnet']['id'])
|
self.assertEqual(ips[1]['subnet_id'], subnet['subnet']['id'])
|
||||||
|
|
||||||
def test_update_port_update_ips(self):
|
def test_update_port_update_ips(self):
|
||||||
"""Update IP and generate new IP on port.
|
"""Update IP and associate new IP on port.
|
||||||
|
|
||||||
Check a port update with the specified subnet_id's. A IP address
|
Check a port update with the specified subnet_id's. A IP address
|
||||||
will be allocated for each subnet_id.
|
will be allocated for each subnet_id.
|
||||||
@ -1200,7 +1200,8 @@ fixed_ips=ip_address%%3D%s&fixed_ips=ip_address%%3D%s&fixed_ips=subnet_id%%3D%s
|
|||||||
with self.port(subnet=subnet) as port:
|
with self.port(subnet=subnet) as port:
|
||||||
data = {'port': {'admin_state_up': False,
|
data = {'port': {'admin_state_up': False,
|
||||||
'fixed_ips': [{'subnet_id':
|
'fixed_ips': [{'subnet_id':
|
||||||
subnet['subnet']['id']}]}}
|
subnet['subnet']['id'],
|
||||||
|
'ip_address': '10.0.0.3'}]}}
|
||||||
req = self.new_update_request('ports', data,
|
req = self.new_update_request('ports', data,
|
||||||
port['port']['id'])
|
port['port']['id'])
|
||||||
res = self.deserialize(self.fmt, req.get_response(self.api))
|
res = self.deserialize(self.fmt, req.get_response(self.api))
|
||||||
@ -1227,9 +1228,9 @@ fixed_ips=ip_address%%3D%s&fixed_ips=ip_address%%3D%s&fixed_ips=subnet_id%%3D%s
|
|||||||
data['port']['admin_state_up'])
|
data['port']['admin_state_up'])
|
||||||
ips = res['port']['fixed_ips']
|
ips = res['port']['fixed_ips']
|
||||||
self.assertEqual(len(ips), 2)
|
self.assertEqual(len(ips), 2)
|
||||||
self.assertEqual(ips[0]['ip_address'], '10.0.0.3')
|
self.assertEqual(ips[0]['ip_address'], '10.0.0.2')
|
||||||
self.assertEqual(ips[0]['subnet_id'], subnet['subnet']['id'])
|
self.assertEqual(ips[0]['subnet_id'], subnet['subnet']['id'])
|
||||||
self.assertEqual(ips[1]['ip_address'], '10.0.0.4')
|
self.assertEqual(ips[1]['ip_address'], '10.0.0.3')
|
||||||
self.assertEqual(ips[1]['subnet_id'], subnet['subnet']['id'])
|
self.assertEqual(ips[1]['subnet_id'], subnet['subnet']['id'])
|
||||||
|
|
||||||
def test_requested_duplicate_mac(self):
|
def test_requested_duplicate_mac(self):
|
||||||
@ -1634,57 +1635,6 @@ fixed_ips=ip_address%%3D%s&fixed_ips=ip_address%%3D%s&fixed_ips=subnet_id%%3D%s
|
|||||||
res = port_req.get_response(self.api)
|
res = port_req.get_response(self.api)
|
||||||
self.assertEqual(res.status_int, 400)
|
self.assertEqual(res.status_int, 400)
|
||||||
|
|
||||||
def test_default_allocation_expiration(self):
|
|
||||||
cfg.CONF.set_override('dhcp_lease_duration', 120)
|
|
||||||
reference = datetime.datetime(2012, 8, 13, 23, 11, 0)
|
|
||||||
|
|
||||||
with mock.patch.object(timeutils, 'utcnow') as mock_utcnow:
|
|
||||||
mock_utcnow.return_value = reference
|
|
||||||
|
|
||||||
plugin = NeutronManager.get_plugin()
|
|
||||||
expires = plugin._default_allocation_expiration()
|
|
||||||
self.assertEqual(expires,
|
|
||||||
reference + datetime.timedelta(seconds=120))
|
|
||||||
|
|
||||||
def test_update_fixed_ip_lease_expiration(self):
|
|
||||||
cfg.CONF.set_override('dhcp_lease_duration', 10)
|
|
||||||
plugin = NeutronManager.get_plugin()
|
|
||||||
with self.subnet() as subnet:
|
|
||||||
with self.port(subnet=subnet) as port:
|
|
||||||
update_context = context.Context('', port['port']['tenant_id'])
|
|
||||||
plugin.update_fixed_ip_lease_expiration(
|
|
||||||
update_context,
|
|
||||||
subnet['subnet']['network_id'],
|
|
||||||
port['port']['fixed_ips'][0]['ip_address'],
|
|
||||||
500)
|
|
||||||
|
|
||||||
q = update_context.session.query(models_v2.IPAllocation)
|
|
||||||
q = q.filter_by(
|
|
||||||
port_id=port['port']['id'],
|
|
||||||
ip_address=port['port']['fixed_ips'][0]['ip_address'])
|
|
||||||
|
|
||||||
ip_allocation = q.one()
|
|
||||||
|
|
||||||
self.assertThat(
|
|
||||||
ip_allocation.expiration - timeutils.utcnow(),
|
|
||||||
matchers.GreaterThan(datetime.timedelta(seconds=10)))
|
|
||||||
|
|
||||||
def test_port_delete_holds_ip(self):
|
|
||||||
base_class = db_base_plugin_v2.NeutronDbPluginV2
|
|
||||||
with mock.patch.object(base_class, '_hold_ip') as hold_ip:
|
|
||||||
with self.subnet() as subnet:
|
|
||||||
with self.port(subnet=subnet, no_delete=True) as port:
|
|
||||||
req = self.new_delete_request('ports', port['port']['id'])
|
|
||||||
res = req.get_response(self.api)
|
|
||||||
self.assertEqual(res.status_int, 204)
|
|
||||||
|
|
||||||
hold_ip.assert_called_once_with(
|
|
||||||
mock.ANY,
|
|
||||||
port['port']['network_id'],
|
|
||||||
port['port']['fixed_ips'][0]['subnet_id'],
|
|
||||||
port['port']['id'],
|
|
||||||
port['port']['fixed_ips'][0]['ip_address'])
|
|
||||||
|
|
||||||
def test_update_fixed_ip_lease_expiration_invalid_address(self):
|
def test_update_fixed_ip_lease_expiration_invalid_address(self):
|
||||||
cfg.CONF.set_override('dhcp_lease_duration', 10)
|
cfg.CONF.set_override('dhcp_lease_duration', 10)
|
||||||
plugin = NeutronManager.get_plugin()
|
plugin = NeutronManager.get_plugin()
|
||||||
@ -1699,27 +1649,6 @@ fixed_ips=ip_address%%3D%s&fixed_ips=ip_address%%3D%s&fixed_ips=subnet_id%%3D%s
|
|||||||
120)
|
120)
|
||||||
self.assertTrue(log.mock_calls)
|
self.assertTrue(log.mock_calls)
|
||||||
|
|
||||||
def test_hold_ip_address(self):
|
|
||||||
plugin = NeutronManager.get_plugin()
|
|
||||||
with self.subnet() as subnet:
|
|
||||||
with self.port(subnet=subnet) as port:
|
|
||||||
update_context = context.Context('', port['port']['tenant_id'])
|
|
||||||
port_id = port['port']['id']
|
|
||||||
with mock.patch.object(db_base_plugin_v2, 'LOG') as log:
|
|
||||||
ip_address = port['port']['fixed_ips'][0]['ip_address']
|
|
||||||
plugin._hold_ip(
|
|
||||||
update_context,
|
|
||||||
subnet['subnet']['network_id'],
|
|
||||||
subnet['subnet']['id'],
|
|
||||||
port_id,
|
|
||||||
ip_address)
|
|
||||||
self.assertTrue(log.mock_calls)
|
|
||||||
|
|
||||||
q = update_context.session.query(models_v2.IPAllocation)
|
|
||||||
q = q.filter_by(port_id=None, ip_address=ip_address)
|
|
||||||
|
|
||||||
self.assertEqual(q.count(), 1)
|
|
||||||
|
|
||||||
def test_recycle_ip_address_without_allocation_pool(self):
|
def test_recycle_ip_address_without_allocation_pool(self):
|
||||||
plugin = NeutronManager.get_plugin()
|
plugin = NeutronManager.get_plugin()
|
||||||
allocation_pools = [{"start": '10.0.0.10',
|
allocation_pools = [{"start": '10.0.0.10',
|
||||||
@ -1742,47 +1671,6 @@ fixed_ips=ip_address%%3D%s&fixed_ips=ip_address%%3D%s&fixed_ips=subnet_id%%3D%s
|
|||||||
q = q.filter_by(subnet_id=subnet_id)
|
q = q.filter_by(subnet_id=subnet_id)
|
||||||
self.assertEqual(q.count(), 0)
|
self.assertEqual(q.count(), 0)
|
||||||
|
|
||||||
def test_recycle_held_ip_address(self):
|
|
||||||
plugin = NeutronManager.get_plugin()
|
|
||||||
with self.subnet() as subnet:
|
|
||||||
with self.port(subnet=subnet) as port:
|
|
||||||
update_context = context.Context('', port['port']['tenant_id'])
|
|
||||||
port_id = port['port']['id']
|
|
||||||
port_obj = plugin._get_port(update_context, port_id)
|
|
||||||
|
|
||||||
for fixed_ip in port_obj.fixed_ips:
|
|
||||||
fixed_ip.active = False
|
|
||||||
fixed_ip.expiration = datetime.datetime.utcnow()
|
|
||||||
|
|
||||||
with mock.patch.object(plugin, '_recycle_ip') as rc:
|
|
||||||
plugin._recycle_expired_ip_allocations(
|
|
||||||
update_context, subnet['subnet']['network_id'])
|
|
||||||
rc.assertEqual(len(rc.mock_calls), 1)
|
|
||||||
self.assertEqual(update_context._recycled_networks,
|
|
||||||
set([subnet['subnet']['network_id']]))
|
|
||||||
|
|
||||||
def test_recycle_expired_previously_run_within_context(self):
|
|
||||||
plugin = NeutronManager.get_plugin()
|
|
||||||
with self.subnet() as subnet:
|
|
||||||
with self.port(subnet=subnet) as port:
|
|
||||||
update_context = context.Context('', port['port']['tenant_id'])
|
|
||||||
port_id = port['port']['id']
|
|
||||||
port_obj = plugin._get_port(update_context, port_id)
|
|
||||||
|
|
||||||
update_context._recycled_networks = set(
|
|
||||||
[subnet['subnet']['network_id']])
|
|
||||||
|
|
||||||
for fixed_ip in port_obj.fixed_ips:
|
|
||||||
fixed_ip.active = False
|
|
||||||
fixed_ip.expiration = datetime.datetime.utcnow()
|
|
||||||
|
|
||||||
with mock.patch.object(plugin, '_recycle_ip') as rc:
|
|
||||||
plugin._recycle_expired_ip_allocations(
|
|
||||||
update_context, subnet['subnet']['network_id'])
|
|
||||||
rc.assertFalse(rc.called)
|
|
||||||
self.assertEqual(update_context._recycled_networks,
|
|
||||||
set([subnet['subnet']['network_id']]))
|
|
||||||
|
|
||||||
def test_max_fixed_ips_exceeded(self):
|
def test_max_fixed_ips_exceeded(self):
|
||||||
with self.subnet(gateway_ip='10.0.0.3',
|
with self.subnet(gateway_ip='10.0.0.3',
|
||||||
cidr='10.0.0.0/24') as subnet:
|
cidr='10.0.0.0/24') as subnet:
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
|
|
||||||
import copy
|
import copy
|
||||||
import os
|
import os
|
||||||
import socket
|
|
||||||
import sys
|
import sys
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
@ -33,7 +32,6 @@ from neutron.agent.linux import dhcp
|
|||||||
from neutron.agent.linux import interface
|
from neutron.agent.linux import interface
|
||||||
from neutron.common import constants
|
from neutron.common import constants
|
||||||
from neutron.common import exceptions
|
from neutron.common import exceptions
|
||||||
from neutron.openstack.common import jsonutils
|
|
||||||
from neutron.tests import base
|
from neutron.tests import base
|
||||||
|
|
||||||
|
|
||||||
@ -99,7 +97,8 @@ fake_port1 = FakeModel('12345678-1234-aaaa-1234567890ab',
|
|||||||
|
|
||||||
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',
|
||||||
network_id='12345678-1234-5678-1234567890ab')
|
network_id='12345678-1234-5678-1234567890ab',
|
||||||
|
fixed_ips=[])
|
||||||
|
|
||||||
fake_meta_port = FakeModel('12345678-1234-aaaa-1234567890ab',
|
fake_meta_port = FakeModel('12345678-1234-aaaa-1234567890ab',
|
||||||
mac_address='aa:bb:cc:dd:ee:ff',
|
mac_address='aa:bb:cc:dd:ee:ff',
|
||||||
@ -147,7 +146,6 @@ class TestDhcpAgent(base.BaseTestCase):
|
|||||||
|
|
||||||
def test_dhcp_agent_manager(self):
|
def test_dhcp_agent_manager(self):
|
||||||
state_rpc_str = 'neutron.agent.rpc.PluginReportStateAPI'
|
state_rpc_str = 'neutron.agent.rpc.PluginReportStateAPI'
|
||||||
lease_relay_str = 'neutron.agent.dhcp_agent.DhcpLeaseRelay'
|
|
||||||
with mock.patch.object(DhcpAgentWithStateReport,
|
with mock.patch.object(DhcpAgentWithStateReport,
|
||||||
'sync_state',
|
'sync_state',
|
||||||
autospec=True) as mock_sync_state:
|
autospec=True) as mock_sync_state:
|
||||||
@ -155,7 +153,6 @@ class TestDhcpAgent(base.BaseTestCase):
|
|||||||
'periodic_resync',
|
'periodic_resync',
|
||||||
autospec=True) as mock_periodic_resync:
|
autospec=True) as mock_periodic_resync:
|
||||||
with mock.patch(state_rpc_str) as state_rpc:
|
with mock.patch(state_rpc_str) as state_rpc:
|
||||||
with mock.patch(lease_relay_str) as mock_lease_relay:
|
|
||||||
with mock.patch.object(sys, 'argv') as sys_argv:
|
with mock.patch.object(sys, 'argv') as sys_argv:
|
||||||
sys_argv.return_value = [
|
sys_argv.return_value = [
|
||||||
'dhcp', '--config-file',
|
'dhcp', '--config-file',
|
||||||
@ -165,8 +162,6 @@ class TestDhcpAgent(base.BaseTestCase):
|
|||||||
config.register_root_helper(cfg.CONF)
|
config.register_root_helper(cfg.CONF)
|
||||||
cfg.CONF.register_opts(
|
cfg.CONF.register_opts(
|
||||||
dhcp_agent.DeviceManager.OPTS)
|
dhcp_agent.DeviceManager.OPTS)
|
||||||
cfg.CONF.register_opts(
|
|
||||||
dhcp_agent.DhcpLeaseRelay.OPTS)
|
|
||||||
cfg.CONF.register_opts(dhcp.OPTS)
|
cfg.CONF.register_opts(dhcp.OPTS)
|
||||||
cfg.CONF.register_opts(interface.OPTS)
|
cfg.CONF.register_opts(interface.OPTS)
|
||||||
cfg.CONF(project='neutron')
|
cfg.CONF(project='neutron')
|
||||||
@ -174,15 +169,11 @@ class TestDhcpAgent(base.BaseTestCase):
|
|||||||
eventlet.greenthread.sleep(1)
|
eventlet.greenthread.sleep(1)
|
||||||
agent_mgr.after_start()
|
agent_mgr.after_start()
|
||||||
mock_sync_state.assert_called_once_with(agent_mgr)
|
mock_sync_state.assert_called_once_with(agent_mgr)
|
||||||
mock_periodic_resync.assert_called_once_with(
|
mock_periodic_resync.assert_called_once_with(agent_mgr)
|
||||||
agent_mgr)
|
|
||||||
state_rpc.assert_has_calls(
|
state_rpc.assert_has_calls(
|
||||||
[mock.call(mock.ANY),
|
[mock.call(mock.ANY),
|
||||||
mock.call().report_state(mock.ANY, mock.ANY,
|
mock.call().report_state(mock.ANY, mock.ANY,
|
||||||
mock.ANY)])
|
mock.ANY)])
|
||||||
mock_lease_relay.assert_has_calls(
|
|
||||||
[mock.call(mock.ANY),
|
|
||||||
mock.call().start()])
|
|
||||||
|
|
||||||
def test_dhcp_agent_main_agent_manager(self):
|
def test_dhcp_agent_main_agent_manager(self):
|
||||||
logging_str = 'neutron.agent.common.config.setup_logging'
|
logging_str = 'neutron.agent.common.config.setup_logging'
|
||||||
@ -202,13 +193,11 @@ class TestDhcpAgent(base.BaseTestCase):
|
|||||||
dhcp = dhcp_agent.DhcpAgent(HOSTNAME)
|
dhcp = dhcp_agent.DhcpAgent(HOSTNAME)
|
||||||
attrs_to_mock = dict(
|
attrs_to_mock = dict(
|
||||||
[(a, mock.DEFAULT) for a in
|
[(a, mock.DEFAULT) for a in
|
||||||
['sync_state', 'lease_relay', 'periodic_resync']])
|
['sync_state', 'periodic_resync']])
|
||||||
with mock.patch.multiple(dhcp, **attrs_to_mock) as mocks:
|
with mock.patch.multiple(dhcp, **attrs_to_mock) as mocks:
|
||||||
dhcp.run()
|
dhcp.run()
|
||||||
mocks['sync_state'].assert_called_once_with()
|
mocks['sync_state'].assert_called_once_with()
|
||||||
mocks['periodic_resync'].assert_called_once_with()
|
mocks['periodic_resync'].assert_called_once_with()
|
||||||
mocks['lease_relay'].assert_has_mock_calls(
|
|
||||||
[mock.call.start()])
|
|
||||||
|
|
||||||
def test_ns_name(self):
|
def test_ns_name(self):
|
||||||
with mock.patch('neutron.agent.dhcp_agent.DeviceManager'):
|
with mock.patch('neutron.agent.dhcp_agent.DeviceManager'):
|
||||||
@ -255,28 +244,6 @@ class TestDhcpAgent(base.BaseTestCase):
|
|||||||
self.assertEqual(log.call_count, 1)
|
self.assertEqual(log.call_count, 1)
|
||||||
self.assertTrue(dhcp.needs_resync)
|
self.assertTrue(dhcp.needs_resync)
|
||||||
|
|
||||||
def test_update_lease(self):
|
|
||||||
with mock.patch('neutron.agent.dhcp_agent.DhcpPluginApi') as plug:
|
|
||||||
dhcp = dhcp_agent.DhcpAgent(HOSTNAME)
|
|
||||||
dhcp.update_lease('net_id', '192.168.1.1', 120)
|
|
||||||
plug.assert_has_calls(
|
|
||||||
[mock.call().update_lease_expiration(
|
|
||||||
'net_id', '192.168.1.1', 120)])
|
|
||||||
|
|
||||||
def test_update_lease_failure(self):
|
|
||||||
with mock.patch('neutron.agent.dhcp_agent.DhcpPluginApi') as plug:
|
|
||||||
plug.return_value.update_lease_expiration.side_effect = Exception
|
|
||||||
|
|
||||||
with mock.patch.object(dhcp_agent.LOG, 'exception') as log:
|
|
||||||
dhcp = dhcp_agent.DhcpAgent(HOSTNAME)
|
|
||||||
dhcp.update_lease('net_id', '192.168.1.1', 120)
|
|
||||||
plug.assert_has_calls(
|
|
||||||
[mock.call().update_lease_expiration(
|
|
||||||
'net_id', '192.168.1.1', 120)])
|
|
||||||
|
|
||||||
self.assertTrue(log.called)
|
|
||||||
self.assertTrue(dhcp.needs_resync)
|
|
||||||
|
|
||||||
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()
|
||||||
@ -425,7 +392,6 @@ class TestDhcpAgentEventHandler(base.BaseTestCase):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestDhcpAgentEventHandler, self).setUp()
|
super(TestDhcpAgentEventHandler, self).setUp()
|
||||||
cfg.CONF.register_opts(dhcp_agent.DeviceManager.OPTS)
|
cfg.CONF.register_opts(dhcp_agent.DeviceManager.OPTS)
|
||||||
cfg.CONF.register_opts(dhcp_agent.DhcpLeaseRelay.OPTS)
|
|
||||||
cfg.CONF.register_opts(dhcp.OPTS)
|
cfg.CONF.register_opts(dhcp.OPTS)
|
||||||
cfg.CONF.set_override('interface_driver',
|
cfg.CONF.set_override('interface_driver',
|
||||||
'neutron.agent.linux.interface.NullDriver')
|
'neutron.agent.linux.interface.NullDriver')
|
||||||
@ -754,26 +720,52 @@ class TestDhcpAgentEventHandler(base.BaseTestCase):
|
|||||||
def test_port_update_end(self):
|
def test_port_update_end(self):
|
||||||
payload = dict(port=vars(fake_port2))
|
payload = dict(port=vars(fake_port2))
|
||||||
self.cache.get_network_by_id.return_value = fake_network
|
self.cache.get_network_by_id.return_value = fake_network
|
||||||
|
self.cache.get_port_by_id.return_value = fake_port2
|
||||||
self.dhcp.port_update_end(None, payload)
|
self.dhcp.port_update_end(None, payload)
|
||||||
self.cache.assert_has_calls(
|
self.cache.assert_has_calls(
|
||||||
[mock.call.get_network_by_id(fake_port2.network_id),
|
[mock.call.get_network_by_id(fake_port2.network_id),
|
||||||
|
mock.call.get_port_by_id(fake_port2.id),
|
||||||
mock.call.put_port(mock.ANY)])
|
mock.call.put_port(mock.ANY)])
|
||||||
self.call_driver.assert_called_once_with('reload_allocations',
|
self.call_driver.assert_called_once_with('reload_allocations',
|
||||||
fake_network)
|
fake_network)
|
||||||
|
|
||||||
|
def test_port_update_change_ip_on_port(self):
|
||||||
|
payload = dict(port=vars(fake_port1))
|
||||||
|
self.cache.get_network_by_id.return_value = fake_network
|
||||||
|
updated_fake_port1 = copy.deepcopy(fake_port1)
|
||||||
|
updated_fake_port1.fixed_ips[0].ip_address = '172.9.9.99'
|
||||||
|
self.cache.get_port_by_id.return_value = updated_fake_port1
|
||||||
|
self.dhcp.port_update_end(None, payload)
|
||||||
|
self.cache.assert_has_calls(
|
||||||
|
[mock.call.get_network_by_id(fake_port1.network_id),
|
||||||
|
mock.call.get_port_by_id(fake_port1.id),
|
||||||
|
mock.call.put_port(mock.ANY)])
|
||||||
|
self.call_driver.assert_has_calls(
|
||||||
|
[mock.call.call_driver(
|
||||||
|
'release_lease',
|
||||||
|
fake_network,
|
||||||
|
mac_address=fake_port1.mac_address,
|
||||||
|
removed_ips=set([updated_fake_port1.fixed_ips[0].ip_address])),
|
||||||
|
mock.call.call_driver('reload_allocations', fake_network)])
|
||||||
|
|
||||||
def test_port_delete_end(self):
|
def test_port_delete_end(self):
|
||||||
payload = dict(port_id=fake_port2.id)
|
payload = dict(port_id=fake_port2.id)
|
||||||
self.cache.get_network_by_id.return_value = fake_network
|
self.cache.get_network_by_id.return_value = fake_network
|
||||||
self.cache.get_port_by_id.return_value = fake_port2
|
self.cache.get_port_by_id.return_value = fake_port2
|
||||||
|
|
||||||
self.dhcp.port_delete_end(None, payload)
|
self.dhcp.port_delete_end(None, payload)
|
||||||
|
removed_ips = [fixed_ip.ip_address
|
||||||
|
for fixed_ip in fake_port2.fixed_ips]
|
||||||
self.cache.assert_has_calls(
|
self.cache.assert_has_calls(
|
||||||
[mock.call.get_port_by_id(fake_port2.id),
|
[mock.call.get_port_by_id(fake_port2.id),
|
||||||
mock.call.get_network_by_id(fake_network.id),
|
mock.call.get_network_by_id(fake_network.id),
|
||||||
mock.call.remove_port(fake_port2)])
|
mock.call.remove_port(fake_port2)])
|
||||||
self.call_driver.assert_called_once_with('reload_allocations',
|
self.call_driver.assert_has_calls(
|
||||||
fake_network)
|
[mock.call.call_driver('release_lease',
|
||||||
|
fake_network,
|
||||||
|
mac_address=fake_port2.mac_address,
|
||||||
|
removed_ips=removed_ips),
|
||||||
|
mock.call.call_driver('reload_allocations', fake_network)])
|
||||||
|
|
||||||
def test_port_delete_end_unknown_port(self):
|
def test_port_delete_end_unknown_port(self):
|
||||||
payload = dict(port_id='unknown')
|
payload = dict(port_id='unknown')
|
||||||
@ -865,16 +857,6 @@ class TestDhcpPluginApiProxy(base.BaseTestCase):
|
|||||||
device_id='devid',
|
device_id='devid',
|
||||||
host='foo')
|
host='foo')
|
||||||
|
|
||||||
def test_update_lease_expiration(self):
|
|
||||||
with mock.patch.object(self.proxy, 'cast') as mock_cast:
|
|
||||||
self.proxy.update_lease_expiration('netid', 'ipaddr', 1)
|
|
||||||
self.assertTrue(mock_cast.called)
|
|
||||||
self.make_msg.assert_called_once_with('update_lease_expiration',
|
|
||||||
network_id='netid',
|
|
||||||
ip_address='ipaddr',
|
|
||||||
lease_remaining=1,
|
|
||||||
host='foo')
|
|
||||||
|
|
||||||
|
|
||||||
class TestNetworkCache(base.BaseTestCase):
|
class TestNetworkCache(base.BaseTestCase):
|
||||||
def test_put_network(self):
|
def test_put_network(self):
|
||||||
@ -1363,123 +1345,6 @@ class TestDeviceManager(base.BaseTestCase):
|
|||||||
device.route.add_gateway.assert_called_once_with('192.168.1.1')
|
device.route.add_gateway.assert_called_once_with('192.168.1.1')
|
||||||
|
|
||||||
|
|
||||||
class TestDhcpLeaseRelay(base.BaseTestCase):
|
|
||||||
def setUp(self):
|
|
||||||
super(TestDhcpLeaseRelay, self).setUp()
|
|
||||||
cfg.CONF.register_opts(dhcp_agent.DhcpLeaseRelay.OPTS)
|
|
||||||
self.unlink_p = mock.patch('os.unlink')
|
|
||||||
self.unlink = self.unlink_p.start()
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
self.unlink_p.stop()
|
|
||||||
super(TestDhcpLeaseRelay, self).tearDown()
|
|
||||||
|
|
||||||
def test_init_relay_socket_path_no_prev_socket(self):
|
|
||||||
with mock.patch('os.path.exists') as exists:
|
|
||||||
exists.return_value = False
|
|
||||||
self.unlink.side_effect = OSError
|
|
||||||
|
|
||||||
dhcp_agent.DhcpLeaseRelay(None)
|
|
||||||
|
|
||||||
self.unlink.assert_called_once_with(
|
|
||||||
cfg.CONF.dhcp_lease_relay_socket)
|
|
||||||
exists.assert_called_once_with(cfg.CONF.dhcp_lease_relay_socket)
|
|
||||||
|
|
||||||
def test_init_relay_socket_path_prev_socket_exists(self):
|
|
||||||
with mock.patch('os.path.exists') as exists:
|
|
||||||
exists.return_value = False
|
|
||||||
|
|
||||||
dhcp_agent.DhcpLeaseRelay(None)
|
|
||||||
|
|
||||||
self.unlink.assert_called_once_with(
|
|
||||||
cfg.CONF.dhcp_lease_relay_socket)
|
|
||||||
self.assertFalse(exists.called)
|
|
||||||
|
|
||||||
def test_init_relay_socket_path_prev_socket_unlink_failure(self):
|
|
||||||
self.unlink.side_effect = OSError
|
|
||||||
with mock.patch('os.path.exists') as exists:
|
|
||||||
exists.return_value = True
|
|
||||||
with testtools.ExpectedException(OSError):
|
|
||||||
dhcp_agent.DhcpLeaseRelay(None)
|
|
||||||
|
|
||||||
self.unlink.assert_called_once_with(
|
|
||||||
cfg.CONF.dhcp_lease_relay_socket)
|
|
||||||
exists.assert_called_once_with(
|
|
||||||
cfg.CONF.dhcp_lease_relay_socket)
|
|
||||||
|
|
||||||
def test_handler_valid_data(self):
|
|
||||||
network_id = 'cccccccc-cccc-cccc-cccc-cccccccccccc'
|
|
||||||
ip_address = '192.168.1.9'
|
|
||||||
lease_remaining = 120
|
|
||||||
|
|
||||||
json_rep = jsonutils.dumps(dict(network_id=network_id,
|
|
||||||
lease_remaining=lease_remaining,
|
|
||||||
ip_address=ip_address))
|
|
||||||
handler = mock.Mock()
|
|
||||||
mock_sock = mock.Mock()
|
|
||||||
mock_sock.recv.return_value = json_rep
|
|
||||||
|
|
||||||
relay = dhcp_agent.DhcpLeaseRelay(handler)
|
|
||||||
|
|
||||||
relay._handler(mock_sock, mock.Mock())
|
|
||||||
mock_sock.assert_has_calls([mock.call.recv(1024), mock.call.close()])
|
|
||||||
handler.called_once_with(network_id, ip_address, lease_remaining)
|
|
||||||
|
|
||||||
def test_handler_invalid_data(self):
|
|
||||||
network_id = 'cccccccc-cccc-cccc-cccc-cccccccccccc'
|
|
||||||
ip_address = '192.168.x.x'
|
|
||||||
lease_remaining = 120
|
|
||||||
|
|
||||||
json_rep = jsonutils.dumps(
|
|
||||||
dict(network_id=network_id,
|
|
||||||
lease_remaining=lease_remaining,
|
|
||||||
ip_address=ip_address))
|
|
||||||
|
|
||||||
handler = mock.Mock()
|
|
||||||
mock_sock = mock.Mock()
|
|
||||||
mock_sock.recv.return_value = json_rep
|
|
||||||
|
|
||||||
relay = dhcp_agent.DhcpLeaseRelay(handler)
|
|
||||||
|
|
||||||
with mock.patch('neutron.openstack.common.'
|
|
||||||
'uuidutils.is_uuid_like') as validate:
|
|
||||||
validate.return_value = False
|
|
||||||
|
|
||||||
with mock.patch.object(dhcp_agent.LOG, 'warn') as log:
|
|
||||||
|
|
||||||
relay._handler(mock_sock, mock.Mock())
|
|
||||||
mock_sock.assert_has_calls(
|
|
||||||
[mock.call.recv(1024), mock.call.close()])
|
|
||||||
self.assertFalse(handler.called)
|
|
||||||
self.assertTrue(log.called)
|
|
||||||
|
|
||||||
def test_handler_other_exception(self):
|
|
||||||
handler = mock.Mock()
|
|
||||||
mock_sock = mock.Mock()
|
|
||||||
mock_sock.recv.side_effect = Exception
|
|
||||||
|
|
||||||
relay = dhcp_agent.DhcpLeaseRelay(handler)
|
|
||||||
|
|
||||||
with mock.patch.object(dhcp_agent.LOG, 'exception') as log:
|
|
||||||
relay._handler(mock_sock, mock.Mock())
|
|
||||||
mock_sock.assert_has_calls([mock.call.recv(1024)])
|
|
||||||
self.assertFalse(handler.called)
|
|
||||||
self.assertTrue(log.called)
|
|
||||||
|
|
||||||
def test_start(self):
|
|
||||||
with mock.patch.object(dhcp_agent, 'eventlet') as mock_eventlet:
|
|
||||||
handler = mock.Mock()
|
|
||||||
relay = dhcp_agent.DhcpLeaseRelay(handler)
|
|
||||||
relay.start()
|
|
||||||
|
|
||||||
mock_eventlet.assert_has_calls(
|
|
||||||
[mock.call.listen(cfg.CONF.dhcp_lease_relay_socket,
|
|
||||||
family=socket.AF_UNIX),
|
|
||||||
mock.call.spawn(mock_eventlet.serve,
|
|
||||||
mock.call.listen.return_value,
|
|
||||||
relay._handler)])
|
|
||||||
|
|
||||||
|
|
||||||
class TestDictModel(base.BaseTestCase):
|
class TestDictModel(base.BaseTestCase):
|
||||||
def test_basic_dict(self):
|
def test_basic_dict(self):
|
||||||
d = dict(a=1, b=2)
|
d = dict(a=1, b=2)
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import socket
|
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
from oslo.config import cfg
|
from oslo.config import cfg
|
||||||
@ -24,7 +23,6 @@ from oslo.config import cfg
|
|||||||
from neutron.agent.common import config
|
from neutron.agent.common import config
|
||||||
from neutron.agent.linux import dhcp
|
from neutron.agent.linux import dhcp
|
||||||
from neutron.common import config as base_config
|
from neutron.common import config as base_config
|
||||||
from neutron.openstack.common import jsonutils
|
|
||||||
from neutron.tests import base
|
from neutron.tests import base
|
||||||
|
|
||||||
|
|
||||||
@ -184,6 +182,9 @@ class TestDhcpBase(base.BaseTestCase):
|
|||||||
def reload_allocations(self):
|
def reload_allocations(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def release_lease(self):
|
||||||
|
pass
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def active(self):
|
def active(self):
|
||||||
return True
|
return True
|
||||||
@ -209,6 +210,9 @@ class LocalChild(dhcp.DhcpLocalProcess):
|
|||||||
def spawn_process(self):
|
def spawn_process(self):
|
||||||
self.called.append('spawn')
|
self.called.append('spawn')
|
||||||
|
|
||||||
|
def release_lease(self):
|
||||||
|
self.called.append('release_lease')
|
||||||
|
|
||||||
|
|
||||||
class TestBase(base.BaseTestCase):
|
class TestBase(base.BaseTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@ -219,9 +223,6 @@ class TestBase(base.BaseTestCase):
|
|||||||
self.conf = config.setup_conf()
|
self.conf = config.setup_conf()
|
||||||
self.conf.register_opts(base_config.core_opts)
|
self.conf.register_opts(base_config.core_opts)
|
||||||
self.conf.register_opts(dhcp.OPTS)
|
self.conf.register_opts(dhcp.OPTS)
|
||||||
self.conf.register_opt(
|
|
||||||
cfg.StrOpt('dhcp_lease_relay_socket',
|
|
||||||
default='$state_path/dhcp/lease_relay'))
|
|
||||||
self.conf.register_opt(cfg.BoolOpt('enable_isolated_metadata',
|
self.conf.register_opt(cfg.BoolOpt('enable_isolated_metadata',
|
||||||
default=True))
|
default=True))
|
||||||
self.conf(args=args)
|
self.conf(args=args)
|
||||||
@ -230,9 +231,9 @@ class TestBase(base.BaseTestCase):
|
|||||||
|
|
||||||
self.replace_p = mock.patch('neutron.agent.linux.utils.replace_file')
|
self.replace_p = mock.patch('neutron.agent.linux.utils.replace_file')
|
||||||
self.execute_p = mock.patch('neutron.agent.linux.utils.execute')
|
self.execute_p = mock.patch('neutron.agent.linux.utils.execute')
|
||||||
|
self.addCleanup(self.replace_p.stop)
|
||||||
self.addCleanup(self.execute_p.stop)
|
self.addCleanup(self.execute_p.stop)
|
||||||
self.safe = self.replace_p.start()
|
self.safe = self.replace_p.start()
|
||||||
self.addCleanup(self.replace_p.stop)
|
|
||||||
self.execute = self.execute_p.start()
|
self.execute = self.execute_p.start()
|
||||||
|
|
||||||
|
|
||||||
@ -433,7 +434,6 @@ class TestDnsmasq(TestBase):
|
|||||||
'exec',
|
'exec',
|
||||||
'qdhcp-ns',
|
'qdhcp-ns',
|
||||||
'env',
|
'env',
|
||||||
'NEUTRON_RELAY_SOCKET_PATH=/dhcp/lease_relay',
|
|
||||||
'NEUTRON_NETWORK_ID=cccccccc-cccc-cccc-cccc-cccccccccccc',
|
'NEUTRON_NETWORK_ID=cccccccc-cccc-cccc-cccc-cccccccccccc',
|
||||||
'dnsmasq',
|
'dnsmasq',
|
||||||
'--no-hosts',
|
'--no-hosts',
|
||||||
@ -445,11 +445,9 @@ class TestDnsmasq(TestBase):
|
|||||||
'--pid-file=/dhcp/cccccccc-cccc-cccc-cccc-cccccccccccc/pid',
|
'--pid-file=/dhcp/cccccccc-cccc-cccc-cccc-cccccccccccc/pid',
|
||||||
'--dhcp-hostsfile=/dhcp/cccccccc-cccc-cccc-cccc-cccccccccccc/host',
|
'--dhcp-hostsfile=/dhcp/cccccccc-cccc-cccc-cccc-cccccccccccc/host',
|
||||||
'--dhcp-optsfile=/dhcp/cccccccc-cccc-cccc-cccc-cccccccccccc/opts',
|
'--dhcp-optsfile=/dhcp/cccccccc-cccc-cccc-cccc-cccccccccccc/opts',
|
||||||
('--dhcp-script=/usr/local/bin/neutron-dhcp-agent-'
|
|
||||||
'dnsmasq-lease-update'),
|
|
||||||
'--leasefile-ro',
|
'--leasefile-ro',
|
||||||
'--dhcp-range=set:tag0,192.168.0.0,static,120s',
|
'--dhcp-range=set:tag0,192.168.0.0,static,86400s',
|
||||||
'--dhcp-range=set:tag1,fdca:3ba5:a17a:4ba3::,static,120s']
|
'--dhcp-range=set:tag1,fdca:3ba5:a17a:4ba3::,static,86400s']
|
||||||
expected.extend(extra_options)
|
expected.extend(extra_options)
|
||||||
|
|
||||||
self.execute.return_value = ('', '')
|
self.execute.return_value = ('', '')
|
||||||
@ -585,6 +583,17 @@ tag:tag0,option:router""".lstrip()
|
|||||||
|
|
||||||
self.safe.assert_called_once_with('/foo/opts', expected)
|
self.safe.assert_called_once_with('/foo/opts', expected)
|
||||||
|
|
||||||
|
def test_release_lease(self):
|
||||||
|
dm = dhcp.Dnsmasq(self.conf, FakeDualNetwork(), namespace='qdhcp-ns',
|
||||||
|
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)
|
||||||
|
|
||||||
def test_reload_allocations(self):
|
def test_reload_allocations(self):
|
||||||
exp_host_name = '/dhcp/cccccccc-cccc-cccc-cccc-cccccccccccc/host'
|
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,'
|
exp_host_data = ('00:00:80:aa:bb:cc,host-192-168-0-2.openstacklocal,'
|
||||||
@ -693,69 +702,6 @@ tag:tag1,249,%s,%s""".lstrip() % (fake_v6,
|
|||||||
{FakeV4Subnet.id: '192.168.0.1'}
|
{FakeV4Subnet.id: '192.168.0.1'}
|
||||||
)
|
)
|
||||||
|
|
||||||
def _test_lease_relay_script_helper(self, action, lease_remaining,
|
|
||||||
path_exists=True):
|
|
||||||
relay_path = '/dhcp/relay_socket'
|
|
||||||
network_id = 'cccccccc-cccc-cccc-cccc-cccccccccccc'
|
|
||||||
mac_address = 'aa:bb:cc:dd:ee:ff'
|
|
||||||
ip_address = '192.168.1.9'
|
|
||||||
|
|
||||||
json_rep = jsonutils.dumps(dict(network_id=network_id,
|
|
||||||
lease_remaining=lease_remaining,
|
|
||||||
mac_address=mac_address,
|
|
||||||
ip_address=ip_address))
|
|
||||||
|
|
||||||
environ = {
|
|
||||||
'NEUTRON_NETWORK_ID': network_id,
|
|
||||||
'NEUTRON_RELAY_SOCKET_PATH': relay_path,
|
|
||||||
'DNSMASQ_TIME_REMAINING': '120',
|
|
||||||
}
|
|
||||||
|
|
||||||
def fake_environ(name, default=None):
|
|
||||||
return environ.get(name, default)
|
|
||||||
|
|
||||||
with mock.patch('os.environ') as mock_environ:
|
|
||||||
mock_environ.get.side_effect = fake_environ
|
|
||||||
|
|
||||||
with mock.patch.object(dhcp, 'sys') as mock_sys:
|
|
||||||
mock_sys.argv = [
|
|
||||||
'lease-update',
|
|
||||||
action,
|
|
||||||
mac_address,
|
|
||||||
ip_address,
|
|
||||||
]
|
|
||||||
|
|
||||||
with mock.patch('socket.socket') as mock_socket:
|
|
||||||
mock_conn = mock.Mock()
|
|
||||||
mock_socket.return_value = mock_conn
|
|
||||||
|
|
||||||
with mock.patch('os.path.exists') as mock_exists:
|
|
||||||
mock_exists.return_value = path_exists
|
|
||||||
|
|
||||||
dhcp.Dnsmasq.lease_update()
|
|
||||||
|
|
||||||
mock_exists.assert_called_once_with(relay_path)
|
|
||||||
if path_exists:
|
|
||||||
mock_socket.assert_called_once_with(
|
|
||||||
socket.AF_UNIX, socket.SOCK_STREAM)
|
|
||||||
|
|
||||||
mock_conn.assert_has_calls(
|
|
||||||
[mock.call.connect(relay_path),
|
|
||||||
mock.call.send(json_rep),
|
|
||||||
mock.call.close()])
|
|
||||||
|
|
||||||
def test_lease_relay_script_add(self):
|
|
||||||
self._test_lease_relay_script_helper('add', 120)
|
|
||||||
|
|
||||||
def test_lease_relay_script_old(self):
|
|
||||||
self._test_lease_relay_script_helper('old', 120)
|
|
||||||
|
|
||||||
def test_lease_relay_script_del(self):
|
|
||||||
self._test_lease_relay_script_helper('del', 0)
|
|
||||||
|
|
||||||
def test_lease_relay_script_add_socket_missing(self):
|
|
||||||
self._test_lease_relay_script_helper('add', 120, False)
|
|
||||||
|
|
||||||
def test_remove_config_files(self):
|
def test_remove_config_files(self):
|
||||||
net = FakeV4Network()
|
net = FakeV4Network()
|
||||||
path = '/opt/data/neutron/dhcp'
|
path = '/opt/data/neutron/dhcp'
|
||||||
|
@ -73,7 +73,6 @@ console_scripts =
|
|||||||
neutron-db-manage = neutron.db.migration.cli:main
|
neutron-db-manage = neutron.db.migration.cli:main
|
||||||
neutron-debug = neutron.debug.shell:main
|
neutron-debug = neutron.debug.shell:main
|
||||||
neutron-dhcp-agent = neutron.agent.dhcp_agent:main
|
neutron-dhcp-agent = neutron.agent.dhcp_agent:main
|
||||||
neutron-dhcp-agent-dnsmasq-lease-update = neutron.agent.linux.dhcp:Dnsmasq.lease_update
|
|
||||||
neutron-hyperv-agent = neutron.plugins.hyperv.agent.hyperv_neutron_agent:main
|
neutron-hyperv-agent = neutron.plugins.hyperv.agent.hyperv_neutron_agent:main
|
||||||
neutron-l3-agent = neutron.agent.l3_agent:main
|
neutron-l3-agent = neutron.agent.l3_agent:main
|
||||||
neutron-lbaas-agent = neutron.services.loadbalancer.drivers.haproxy.agent:main
|
neutron-lbaas-agent = neutron.services.loadbalancer.drivers.haproxy.agent:main
|
||||||
@ -91,7 +90,6 @@ console_scripts =
|
|||||||
quantum-db-manage = neutron.db.migration.cli:main
|
quantum-db-manage = neutron.db.migration.cli:main
|
||||||
quantum-debug = neutron.debug.shell:main
|
quantum-debug = neutron.debug.shell:main
|
||||||
quantum-dhcp-agent = neutron.agent.dhcp_agent:main
|
quantum-dhcp-agent = neutron.agent.dhcp_agent:main
|
||||||
quantum-dhcp-agent-dnsmasq-lease-update = neutron.agent.linux.dhcp:Dnsmasq.lease_update
|
|
||||||
quantum-hyperv-agent = neutron.plugins.hyperv.agent.hyperv_neutron_agent:main
|
quantum-hyperv-agent = neutron.plugins.hyperv.agent.hyperv_neutron_agent:main
|
||||||
quantum-l3-agent = neutron.agent.l3_agent:main
|
quantum-l3-agent = neutron.agent.l3_agent:main
|
||||||
quantum-lbaas-agent = neutron.services.loadbalancer.drivers.haproxy.agent:main
|
quantum-lbaas-agent = neutron.services.loadbalancer.drivers.haproxy.agent:main
|
||||||
|
Loading…
x
Reference in New Issue
Block a user