diff --git a/bin/neutron-dhcp-agent-dnsmasq-lease-update b/bin/neutron-dhcp-agent-dnsmasq-lease-update deleted file mode 100755 index 41bbbe382d..0000000000 --- a/bin/neutron-dhcp-agent-dnsmasq-lease-update +++ /dev/null @@ -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() diff --git a/etc/neutron.conf b/etc/neutron.conf index 8cdaa1d657..9f66b8cbde 100644 --- a/etc/neutron.conf +++ b/etc/neutron.conf @@ -69,7 +69,7 @@ lock_path = $state_path/lock # mac_generation_retries = 16 # DHCP Lease duration (in seconds) -# dhcp_lease_duration = 120 +# dhcp_lease_duration = 86400 # Allow sending resource operation notification to DHCP agent # dhcp_agent_notification = True diff --git a/etc/neutron/rootwrap.d/dhcp.filters b/etc/neutron/rootwrap.d/dhcp.filters index e615ddb9a3..26e2e56643 100644 --- a/etc/neutron/rootwrap.d/dhcp.filters +++ b/etc/neutron/rootwrap.d/dhcp.filters @@ -9,7 +9,7 @@ [Filters] # 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 # it looks like these are the only signals needed, per # 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 ovs-vsctl: CommandFilter, ovs-vsctl, root ivs-ctl: CommandFilter, ivs-ctl, root +dhcp_release: CommandFilter, dhcp_release, root # metadata proxy metadata_proxy: CommandFilter, neutron-ns-metadata-proxy, root diff --git a/neutron/agent/dhcp_agent.py b/neutron/agent/dhcp_agent.py index 627bcca62e..a826d2f312 100644 --- a/neutron/agent/dhcp_agent.py +++ b/neutron/agent/dhcp_agent.py @@ -37,12 +37,10 @@ from neutron.common import utils from neutron import context from neutron import manager 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 loopingcall from neutron.openstack.common.rpc import proxy from neutron.openstack.common import service -from neutron.openstack.common import uuidutils from neutron import service as neutron_service LOG = logging.getLogger(__name__) @@ -81,8 +79,10 @@ class DhcpAgent(manager.Manager): ctx = context.get_admin_context_without_session() self.plugin_rpc = DhcpPluginApi(topics.PLUGIN, ctx) 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._populate_networks_cache() @@ -114,13 +114,12 @@ class DhcpAgent(manager.Manager): """Activate the DHCP agent.""" self.sync_state() self.periodic_resync() - self.lease_relay.start() def _ns_name(self, network): if self.conf.use_namespaces: 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.""" try: # the Driver expects something that is duck typed similar to @@ -131,21 +130,13 @@ class DhcpAgent(manager.Manager): self.device_manager, self._ns_name(network), self.dhcp_version) - getattr(driver, action)() + getattr(driver, action)(**action_kwargs) return True except Exception: self.needs_resync = True 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): """Sync the local DHCP state with Neutron.""" LOG.info(_('Synchronizing state')) @@ -246,6 +237,22 @@ class DhcpAgent(manager.Manager): if new_cidrs: 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') def network_create_end(self, context, payload): """Handle the network.create.end notification event.""" @@ -289,6 +296,7 @@ class DhcpAgent(manager.Manager): port = DictModel(payload['port']) network = self.cache.get_network_by_id(port.network_id) if network: + self.release_lease_for_removed_ips(port, network) self.cache.put_port(port) self.call_driver('reload_allocations', network) @@ -302,6 +310,12 @@ class DhcpAgent(manager.Manager): if port: network = self.cache.get_network_by_id(port.network_id) 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) def enable_isolated_metadata_proxy(self, network): @@ -435,16 +449,6 @@ class DhcpPluginApi(proxy.RpcProxy): host=self.host), 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): """Agent cache of the current network state.""" @@ -747,67 +751,6 @@ class DictModel(object): 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): def __init__(self, host=None): super(DhcpAgentWithStateReport, self).__init__(host=host) @@ -863,7 +806,6 @@ def register_options(): config.register_agent_state_opts_helper(cfg.CONF) config.register_root_helper(cfg.CONF) cfg.CONF.register_opts(DeviceManager.OPTS) - cfg.CONF.register_opts(DhcpLeaseRelay.OPTS) cfg.CONF.register_opts(dhcp.OPTS) cfg.CONF.register_opts(interface.OPTS) diff --git a/neutron/agent/linux/dhcp.py b/neutron/agent/linux/dhcp.py index ef10b35f8e..9ea49bb7b7 100644 --- a/neutron/agent/linux/dhcp.py +++ b/neutron/agent/linux/dhcp.py @@ -89,6 +89,10 @@ class DhcpBase(object): def active(self): """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 def reload_allocations(self): """Force the DHCP server to reload the assignment database.""" @@ -261,8 +265,6 @@ class Dnsmasq(DhcpLocalProcess): """Spawns a Dnsmasq process for the network.""" env = { self.NEUTRON_NETWORK_ID_KEY: self.network.id, - self.NEUTRON_RELAY_SOCKET_PATH_KEY: - self.conf.dhcp_lease_relay_socket } cmd = [ @@ -279,7 +281,6 @@ class Dnsmasq(DhcpLocalProcess): #'--dhcp-lease-max=%s' % ?, '--dhcp-hostsfile=%s' % self._output_hosts_file(), '--dhcp-optsfile=%s' % self._output_opts_file(), - '--dhcp-script=%s' % self._lease_relay_script_path(), '--leasefile-ro', ] @@ -318,6 +319,16 @@ class Dnsmasq(DhcpLocalProcess): cmd = ['%s=%s' % pair for pair in env.items()] + cmd 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): """Rebuild the dnsmasq config and signal the dnsmasq to reload.""" @@ -428,10 +439,6 @@ class Dnsmasq(DhcpLocalProcess): 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): """Format DHCP option by option name or code.""" if self.version >= self.MINIMUM_VERSION: diff --git a/neutron/common/config.py b/neutron/common/config.py index 6bbe080b73..4f0eb47bf0 100644 --- a/neutron/common/config.py +++ b/neutron/common/config.py @@ -71,7 +71,7 @@ core_opts = [ help=_("Maximum number of host routes per subnet")), cfg.IntOpt('max_fixed_ips_per_port', default=5, 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', help=_("DHCP lease duration")), cfg.BoolOpt('dhcp_agent_notification', default=True, diff --git a/neutron/db/db_base_plugin_v2.py b/neutron/db/db_base_plugin_v2.py index cbdfbfa5bf..1c76ae3e60 100644 --- a/neutron/db/db_base_plugin_v2.py +++ b/neutron/db/db_base_plugin_v2.py @@ -293,54 +293,6 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2, return True 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 def _recycle_ip(context, network_id, subnet_id, ip_address): """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, 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, ip_address, lease_remaining): @@ -690,11 +637,10 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2, to_add = self._test_fixed_ips_for_port(context, network_id, new_ips) for ip in original_ips: LOG.debug(_("Port update. Hold %s"), ip) - NeutronDbPluginV2._hold_ip(context, - network_id, - ip['subnet_id'], - port_id, - ip['ip_address']) + NeutronDbPluginV2._recycle_ip(context, + network_id, + ip['subnet_id'], + ip['ip_address']) if to_add: LOG.debug(_("Port update. Adding %s"), to_add) @@ -1321,7 +1267,6 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2, tenant_id = self._get_tenant_id_for_create(context, p) with context.session.begin(subtransactions=True): - self._recycle_expired_ip_allocations(context, network_id) network = self._get_network(context, network_id) # 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, ip_address=ip_address, subnet_id=subnet_id, - expiration=self._default_allocation_expiration() ) context.session.add(allocated) @@ -1387,8 +1331,6 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2, # Check if the IPs need to be updated if 'fixed_ips' in p: changed_ips = True - self._recycle_expired_ip_allocations(context, - port['network_id']) original = self._make_port_dict(port, process_extensions=False) added_ips, prev_ips = self._update_ips_for_port( context, port["network_id"], id, original["fixed_ips"], @@ -1398,8 +1340,7 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2, for ip in added_ips: allocated = models_v2.IPAllocation( network_id=port['network_id'], port_id=port.id, - ip_address=ip['ip_address'], subnet_id=ip['subnet_id'], - expiration=self._default_allocation_expiration()) + ip_address=ip['ip_address'], subnet_id=ip['subnet_id']) context.session.add(allocated) # Remove all attributes in p which are not in the port DB model # and then update the port @@ -1428,11 +1369,10 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2, if NeutronDbPluginV2._check_ip_in_allocation_pool( context, a['subnet_id'], subnet['gateway_ip'], a['ip_address']): - NeutronDbPluginV2._hold_ip(context, - a['network_id'], - a['subnet_id'], - id, - a['ip_address']) + NeutronDbPluginV2._recycle_ip(context, + a['network_id'], + a['subnet_id'], + a['ip_address']) else: # IPs out of allocation pool will not be recycled, but # we do need to delete the allocation from the DB diff --git a/neutron/db/dhcp_rpc_base.py b/neutron/db/dhcp_rpc_base.py index fb47be301a..25a2876cdc 100644 --- a/neutron/db/dhcp_rpc_base.py +++ b/neutron/db/dhcp_rpc_base.py @@ -47,8 +47,8 @@ class DhcpRpcCallbackMixin(object): 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. + # left so that neutron-dhcp-agents will still continue to work if + # neutron-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) @@ -97,8 +97,8 @@ class DhcpRpcCallbackMixin(object): """ # 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. + # left so that neutron-dhcp-agents will still continue to work if + # neutron-server is upgraded and not the agent. host = kwargs.get('host') network_id = kwargs.get('network_id') @@ -209,20 +209,13 @@ class DhcpRpcCallbackMixin(object): def update_lease_expiration(self, context, **kwargs): """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') - 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 ' - '%(network_id)s from %(host)s.'), - {'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) + LOG.warning(_('Updating lease expiration is now deprecated. Issued ' + 'from host %(host)s.') % host) def create_dhcp_port(self, context, **kwargs): """Create the dhcp port.""" diff --git a/neutron/db/migration/alembic_migrations/versions/f9263d6df56_remove_dhcp_lease.py b/neutron/db/migration/alembic_migrations/versions/f9263d6df56_remove_dhcp_lease.py new file mode 100644 index 0000000000..e6f38a9b3e --- /dev/null +++ b/neutron/db/migration/alembic_migrations/versions/f9263d6df56_remove_dhcp_lease.py @@ -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)) diff --git a/neutron/db/models_v2.py b/neutron/db/models_v2.py index 8c00ffce54..992bd1374a 100644 --- a/neutron/db/models_v2.py +++ b/neutron/db/models_v2.py @@ -99,7 +99,6 @@ class IPAllocation(model_base.BASEV2): network_id = sa.Column(sa.String(36), sa.ForeignKey("networks.id", ondelete="CASCADE"), nullable=False, primary_key=True) - expiration = sa.Column(sa.DateTime, nullable=True) class Route(object): diff --git a/neutron/tests/unit/test_config.py b/neutron/tests/unit/test_config.py index b43a5ffdf3..cb773ed64d 100644 --- a/neutron/tests/unit/test_config.py +++ b/neutron/tests/unit/test_config.py @@ -41,6 +41,6 @@ class ConfigurationTest(base.BaseTestCase): '..', '..', '..') absolute_dir = os.path.abspath(relative_dir) 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.assertEqual('neutron', cfg.CONF.control_exchange) diff --git a/neutron/tests/unit/test_db_plugin.py b/neutron/tests/unit/test_db_plugin.py index 4a45d34f2b..8eadcf1875 100644 --- a/neutron/tests/unit/test_db_plugin.py +++ b/neutron/tests/unit/test_db_plugin.py @@ -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']) 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 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: data = {'port': {'admin_state_up': False, 'fixed_ips': [{'subnet_id': - subnet['subnet']['id']}]}} + subnet['subnet']['id'], + 'ip_address': '10.0.0.3'}]}} req = self.new_update_request('ports', data, port['port']['id']) 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']) ips = res['port']['fixed_ips'] 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[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']) 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) 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): cfg.CONF.set_override('dhcp_lease_duration', 10) 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) 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): plugin = NeutronManager.get_plugin() 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) 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): with self.subnet(gateway_ip='10.0.0.3', cidr='10.0.0.0/24') as subnet: diff --git a/neutron/tests/unit/test_dhcp_agent.py b/neutron/tests/unit/test_dhcp_agent.py index 675bda03f0..728f7fba55 100644 --- a/neutron/tests/unit/test_dhcp_agent.py +++ b/neutron/tests/unit/test_dhcp_agent.py @@ -17,7 +17,6 @@ import copy import os -import socket import sys import uuid @@ -33,7 +32,6 @@ from neutron.agent.linux import dhcp from neutron.agent.linux import interface from neutron.common import constants from neutron.common import exceptions -from neutron.openstack.common import jsonutils from neutron.tests import base @@ -99,7 +97,8 @@ fake_port1 = FakeModel('12345678-1234-aaaa-1234567890ab', fake_port2 = FakeModel('12345678-1234-aaaa-123456789000', 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', mac_address='aa:bb:cc:dd:ee:ff', @@ -147,7 +146,6 @@ class TestDhcpAgent(base.BaseTestCase): def test_dhcp_agent_manager(self): state_rpc_str = 'neutron.agent.rpc.PluginReportStateAPI' - lease_relay_str = 'neutron.agent.dhcp_agent.DhcpLeaseRelay' with mock.patch.object(DhcpAgentWithStateReport, 'sync_state', autospec=True) as mock_sync_state: @@ -155,34 +153,27 @@ class TestDhcpAgent(base.BaseTestCase): 'periodic_resync', autospec=True) as mock_periodic_resync: 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: - sys_argv.return_value = [ - 'dhcp', '--config-file', - etcdir('neutron.conf.test')] - cfg.CONF.register_opts(dhcp_agent.DhcpAgent.OPTS) - config.register_agent_state_opts_helper(cfg.CONF) - config.register_root_helper(cfg.CONF) - 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(interface.OPTS) - cfg.CONF(project='neutron') - agent_mgr = DhcpAgentWithStateReport('testhost') - eventlet.greenthread.sleep(1) - agent_mgr.after_start() - mock_sync_state.assert_called_once_with(agent_mgr) - mock_periodic_resync.assert_called_once_with( - agent_mgr) - state_rpc.assert_has_calls( - [mock.call(mock.ANY), - mock.call().report_state(mock.ANY, mock.ANY, - mock.ANY)]) - mock_lease_relay.assert_has_calls( - [mock.call(mock.ANY), - mock.call().start()]) + with mock.patch.object(sys, 'argv') as sys_argv: + sys_argv.return_value = [ + 'dhcp', '--config-file', + etcdir('neutron.conf.test')] + cfg.CONF.register_opts(dhcp_agent.DhcpAgent.OPTS) + config.register_agent_state_opts_helper(cfg.CONF) + config.register_root_helper(cfg.CONF) + cfg.CONF.register_opts( + dhcp_agent.DeviceManager.OPTS) + cfg.CONF.register_opts(dhcp.OPTS) + cfg.CONF.register_opts(interface.OPTS) + cfg.CONF(project='neutron') + agent_mgr = DhcpAgentWithStateReport('testhost') + eventlet.greenthread.sleep(1) + agent_mgr.after_start() + mock_sync_state.assert_called_once_with(agent_mgr) + mock_periodic_resync.assert_called_once_with(agent_mgr) + state_rpc.assert_has_calls( + [mock.call(mock.ANY), + mock.call().report_state(mock.ANY, mock.ANY, + mock.ANY)]) def test_dhcp_agent_main_agent_manager(self): logging_str = 'neutron.agent.common.config.setup_logging' @@ -202,13 +193,11 @@ class TestDhcpAgent(base.BaseTestCase): dhcp = dhcp_agent.DhcpAgent(HOSTNAME) attrs_to_mock = dict( [(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: dhcp.run() mocks['sync_state'].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): with mock.patch('neutron.agent.dhcp_agent.DeviceManager'): @@ -255,28 +244,6 @@ class TestDhcpAgent(base.BaseTestCase): self.assertEqual(log.call_count, 1) 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): with mock.patch('neutron.agent.dhcp_agent.DhcpPluginApi') as plug: mock_plugin = mock.Mock() @@ -425,7 +392,6 @@ class TestDhcpAgentEventHandler(base.BaseTestCase): def setUp(self): super(TestDhcpAgentEventHandler, self).setUp() cfg.CONF.register_opts(dhcp_agent.DeviceManager.OPTS) - cfg.CONF.register_opts(dhcp_agent.DhcpLeaseRelay.OPTS) cfg.CONF.register_opts(dhcp.OPTS) cfg.CONF.set_override('interface_driver', 'neutron.agent.linux.interface.NullDriver') @@ -754,26 +720,52 @@ class TestDhcpAgentEventHandler(base.BaseTestCase): def test_port_update_end(self): payload = dict(port=vars(fake_port2)) 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.cache.assert_has_calls( [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)]) self.call_driver.assert_called_once_with('reload_allocations', 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): payload = dict(port_id=fake_port2.id) self.cache.get_network_by_id.return_value = fake_network self.cache.get_port_by_id.return_value = fake_port2 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( [mock.call.get_port_by_id(fake_port2.id), mock.call.get_network_by_id(fake_network.id), mock.call.remove_port(fake_port2)]) - self.call_driver.assert_called_once_with('reload_allocations', - fake_network) + self.call_driver.assert_has_calls( + [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): payload = dict(port_id='unknown') @@ -865,16 +857,6 @@ class TestDhcpPluginApiProxy(base.BaseTestCase): device_id='devid', 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): 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') -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): def test_basic_dict(self): d = dict(a=1, b=2) diff --git a/neutron/tests/unit/test_linux_dhcp.py b/neutron/tests/unit/test_linux_dhcp.py index 22850b42e0..a4471b4098 100644 --- a/neutron/tests/unit/test_linux_dhcp.py +++ b/neutron/tests/unit/test_linux_dhcp.py @@ -16,7 +16,6 @@ # under the License. import os -import socket import mock from oslo.config import cfg @@ -24,7 +23,6 @@ from oslo.config import cfg from neutron.agent.common import config from neutron.agent.linux import dhcp from neutron.common import config as base_config -from neutron.openstack.common import jsonutils from neutron.tests import base @@ -184,6 +182,9 @@ class TestDhcpBase(base.BaseTestCase): def reload_allocations(self): pass + def release_lease(self): + pass + @property def active(self): return True @@ -209,6 +210,9 @@ class LocalChild(dhcp.DhcpLocalProcess): def spawn_process(self): self.called.append('spawn') + def release_lease(self): + self.called.append('release_lease') + class TestBase(base.BaseTestCase): def setUp(self): @@ -219,9 +223,6 @@ class TestBase(base.BaseTestCase): self.conf = config.setup_conf() self.conf.register_opts(base_config.core_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', default=True)) self.conf(args=args) @@ -230,9 +231,9 @@ class TestBase(base.BaseTestCase): self.replace_p = mock.patch('neutron.agent.linux.utils.replace_file') self.execute_p = mock.patch('neutron.agent.linux.utils.execute') + self.addCleanup(self.replace_p.stop) self.addCleanup(self.execute_p.stop) self.safe = self.replace_p.start() - self.addCleanup(self.replace_p.stop) self.execute = self.execute_p.start() @@ -433,7 +434,6 @@ class TestDnsmasq(TestBase): 'exec', 'qdhcp-ns', 'env', - 'NEUTRON_RELAY_SOCKET_PATH=/dhcp/lease_relay', 'NEUTRON_NETWORK_ID=cccccccc-cccc-cccc-cccc-cccccccccccc', 'dnsmasq', '--no-hosts', @@ -445,11 +445,9 @@ class TestDnsmasq(TestBase): '--pid-file=/dhcp/cccccccc-cccc-cccc-cccc-cccccccccccc/pid', '--dhcp-hostsfile=/dhcp/cccccccc-cccc-cccc-cccc-cccccccccccc/host', '--dhcp-optsfile=/dhcp/cccccccc-cccc-cccc-cccc-cccccccccccc/opts', - ('--dhcp-script=/usr/local/bin/neutron-dhcp-agent-' - 'dnsmasq-lease-update'), '--leasefile-ro', - '--dhcp-range=set:tag0,192.168.0.0,static,120s', - '--dhcp-range=set:tag1,fdca:3ba5:a17a:4ba3::,static,120s'] + '--dhcp-range=set:tag0,192.168.0.0,static,86400s', + '--dhcp-range=set:tag1,fdca:3ba5:a17a:4ba3::,static,86400s'] expected.extend(extra_options) self.execute.return_value = ('', '') @@ -585,6 +583,17 @@ tag:tag0,option:router""".lstrip() 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): 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,' @@ -693,69 +702,6 @@ tag:tag1,249,%s,%s""".lstrip() % (fake_v6, {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): net = FakeV4Network() path = '/opt/data/neutron/dhcp' diff --git a/setup.cfg b/setup.cfg index d30b962c5e..4e31862865 100644 --- a/setup.cfg +++ b/setup.cfg @@ -73,7 +73,6 @@ console_scripts = neutron-db-manage = neutron.db.migration.cli:main neutron-debug = neutron.debug.shell: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-l3-agent = neutron.agent.l3_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-debug = neutron.debug.shell: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-l3-agent = neutron.agent.l3_agent:main quantum-lbaas-agent = neutron.services.loadbalancer.drivers.haproxy.agent:main